clone and modify arcade to stop text scale and speed up text display
							
								
								
									
										46
									
								
								arcade/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,46 @@ | ||||
| """ | ||||
| The Arcade Library | ||||
|  | ||||
| A Python simple, easy to use module for creating 2D games. | ||||
| """ | ||||
|  | ||||
| # Error out if we import Arcade with an incompatible version of Python. | ||||
| import sys | ||||
|  | ||||
| if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 6): | ||||
|     sys.exit("The Arcade Library requires Python 3.6 or higher.") | ||||
|  | ||||
| try: | ||||
|     import pyglet_ffmpeg2 | ||||
| except Exception as e: | ||||
|     print("Unable to load the ffmpeg library. ", e) | ||||
|  | ||||
| import pyglet | ||||
|  | ||||
| pyglet.options['shadow_window'] = False | ||||
|  | ||||
| from arcade import color | ||||
| from arcade import csscolor | ||||
| from arcade import key | ||||
| from arcade.application import * | ||||
| from arcade.arcade_types import * | ||||
| from arcade.utils import * | ||||
| from arcade.draw_commands import * | ||||
| from arcade.buffered_draw_commands import * | ||||
| from arcade.geometry import * | ||||
| from arcade.physics_engines import * | ||||
| from arcade.emitter import * | ||||
| from arcade.emitter_simple import * | ||||
| from arcade.particle import * | ||||
| from arcade.sound import * | ||||
| from arcade.sprite import * | ||||
| from arcade.sprite_list import * | ||||
| from arcade.version import * | ||||
| from arcade.window_commands import * | ||||
| from arcade.joysticks import * | ||||
| from arcade.read_tiled_map import * | ||||
| from arcade.isometric import * | ||||
| from arcade.text import draw_text | ||||
| from arcade.text import create_text | ||||
| from arcade.text import render_text | ||||
| from arcade import tilemap | ||||
							
								
								
									
										446
									
								
								arcade/application.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,446 @@ | ||||
| """ | ||||
| The main window class that all object-oriented applications should | ||||
| derive from. | ||||
| """ | ||||
| from numbers import Number | ||||
| from typing import Tuple | ||||
|  | ||||
| import pyglet.gl as gl | ||||
| import pyglet | ||||
|  | ||||
| from arcade.window_commands import (get_viewport, set_viewport, set_window) | ||||
|  | ||||
| MOUSE_BUTTON_LEFT = 1 | ||||
| MOUSE_BUTTON_MIDDLE = 2 | ||||
| MOUSE_BUTTON_RIGHT = 4 | ||||
|  | ||||
|  | ||||
| class NoOpenGLException(Exception): | ||||
|     """ | ||||
|     Exception when we can't get an OpenGL 3.3+ context | ||||
|     """ | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Window(pyglet.window.Window): | ||||
|     """ | ||||
|     The Window class forms the basis of most advanced games that use Arcade. | ||||
|     It represents a window on the screen, and manages events. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width: Number = 800, height: Number = 600, | ||||
|                  title: str = 'Arcade Window', fullscreen: bool = False, | ||||
|                  resizable: bool = False, update_rate=1/60, | ||||
|                  antialiasing: bool = True): | ||||
|         """ | ||||
|         Construct a new window | ||||
|  | ||||
|         :param float width: Window width | ||||
|         :param float height: Window height | ||||
|         :param str title: Title (appears in title bar) | ||||
|         :param bool fullscreen: Should this be full screen? | ||||
|         :param bool resizable: Can the user resize the window? | ||||
|         :param float update_rate: How frequently to update the window. | ||||
|         :param bool antialiasing: Should OpenGL's anti-aliasing be enabled? | ||||
|         """ | ||||
|         if antialiasing: | ||||
|             config = pyglet.gl.Config(major_version=3, | ||||
|                                       minor_version=3, | ||||
|                                       double_buffer=True, | ||||
|                                       sample_buffers=1, | ||||
|                                       samples=4) | ||||
|         else: | ||||
|             config = pyglet.gl.Config(major_version=3, | ||||
|                                       minor_version=3, | ||||
|                                       double_buffer=True) | ||||
|  | ||||
|         try: | ||||
|             super().__init__(width=width, height=height, caption=title, | ||||
|                              resizable=resizable, config=config) | ||||
|         except pyglet.window.NoSuchConfigException: | ||||
|             raise NoOpenGLException("Unable to create an OpenGL 3.3+ context. " | ||||
|                                     "Check to make sure your system supports OpenGL 3.3 or higher.") | ||||
|  | ||||
|         if antialiasing: | ||||
|             try: | ||||
|                 gl.glEnable(gl.GL_MULTISAMPLE_ARB) | ||||
|             except pyglet.gl.GLException: | ||||
|                 print("Warning: Anti-aliasing not supported on this computer.") | ||||
|  | ||||
|         if update_rate: | ||||
|             from pyglet import compat_platform | ||||
|             if compat_platform == 'darwin' or compat_platform == 'linux': | ||||
|                 # Set vsync to false, or we'll be limited to a 1/30 sec update rate possibly | ||||
|                 self.context.set_vsync(False) | ||||
|             self.set_update_rate(update_rate) | ||||
|  | ||||
|         super().set_fullscreen(fullscreen) | ||||
|         self.invalid = False | ||||
|         set_window(self) | ||||
|         set_viewport(0, self.width, 0, self.height) | ||||
|         self.current_view = None | ||||
|  | ||||
|     def update(self, delta_time: float): | ||||
|         """ | ||||
|         Move everything. For better consistency in naming, use ``on_update`` instead. | ||||
|  | ||||
|         :param float delta_time: Time interval since the last time the function was called in seconds. | ||||
|  | ||||
|         """ | ||||
|         try: | ||||
|             self.current_view.update(delta_time) | ||||
|         except AttributeError: | ||||
|             pass | ||||
|  | ||||
|     def on_update(self, delta_time: float): | ||||
|         """ | ||||
|         Move everything. Perform collision checks. Do all the game logic here. | ||||
|  | ||||
|         :param float delta_time: Time interval since the last time the function was called. | ||||
|  | ||||
|         """ | ||||
|         try: | ||||
|             self.current_view.on_update(delta_time) | ||||
|         except AttributeError: | ||||
|             pass | ||||
|  | ||||
|     def set_update_rate(self, rate: float): | ||||
|         """ | ||||
|         Set how often the screen should be updated. | ||||
|         For example, self.set_update_rate(1 / 60) will set the update rate to 60 fps | ||||
|  | ||||
|         :param float rate: Update frequency in seconds | ||||
|         """ | ||||
|         pyglet.clock.unschedule(self.update) | ||||
|         pyglet.clock.schedule_interval(self.update, rate) | ||||
|         pyglet.clock.unschedule(self.on_update) | ||||
|         pyglet.clock.schedule_interval(self.on_update, rate) | ||||
|  | ||||
|     def on_mouse_motion(self, x: float, y: float, dx: float, dy: float): | ||||
|         """ | ||||
|         Override this function to add mouse functionality. | ||||
|  | ||||
|         :param float x: x position of mouse | ||||
|         :param float y: y position of mouse | ||||
|         :param float dx: Change in x since the last time this method was called | ||||
|         :param float dy: Change in y since the last time this method was called | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def on_mouse_press(self, x: float, y: float, button: int, modifiers: int): | ||||
|         """ | ||||
|         Override this function to add mouse button functionality. | ||||
|  | ||||
|         :param float x: x position of the mouse | ||||
|         :param float y: y position of the mouse | ||||
|         :param int button: What button was hit. One of: | ||||
|                            arcade.MOUSE_BUTTON_LEFT, arcade.MOUSE_BUTTON_RIGHT, | ||||
|                            arcade.MOUSE_BUTTON_MIDDLE | ||||
|         :param int modifiers: Shift/click, ctrl/click, etc. | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def on_mouse_drag(self, x: float, y: float, dx: float, dy: float, buttons: int, modifiers: int): | ||||
|         """ | ||||
|         Override this function to add mouse button functionality. | ||||
|  | ||||
|         :param float x: x position of mouse | ||||
|         :param float y: y position of mouse | ||||
|         :param float dx: Change in x since the last time this method was called | ||||
|         :param float dy: Change in y since the last time this method was called | ||||
|         :param int buttons: Which button is pressed | ||||
|         :param int modifiers: Ctrl, shift, etc. | ||||
|         """ | ||||
|         self.on_mouse_motion(x, y, dx, dy) | ||||
|  | ||||
|     def on_mouse_release(self, x: float, y: float, button: int, | ||||
|                          modifiers: int): | ||||
|         """ | ||||
|         Override this function to add mouse button functionality. | ||||
|  | ||||
|         :param float x: | ||||
|         :param float y: | ||||
|         :param int button: | ||||
|         :param int modifiers: | ||||
|         """ | ||||
|  | ||||
|         pass | ||||
|  | ||||
|     def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int): | ||||
|         """ | ||||
|         User moves the scroll wheel. | ||||
|  | ||||
|         :param int x: | ||||
|         :param int y: | ||||
|         :param int scroll_x: | ||||
|         :param int scroll_y: | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def set_mouse_visible(self, visible: bool = True): | ||||
|         """ | ||||
|         If true, user can see the mouse cursor while it is over the window. Set false, | ||||
|         the mouse is not visible. Default is true. | ||||
|  | ||||
|         :param bool visible: | ||||
|         """ | ||||
|         super().set_mouse_visible(visible) | ||||
|  | ||||
|     def on_key_press(self, symbol: int, modifiers: int): | ||||
|         """ | ||||
|         Override this function to add key press functionality. | ||||
|  | ||||
|         :param int symbol: Key that was hit | ||||
|         :param int modifiers: If it was shift/ctrl/alt | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def on_key_release(self, symbol: int, modifiers: int): | ||||
|         """ | ||||
|         Override this function to add key release functionality. | ||||
|  | ||||
|         :param int symbol: Key that was hit | ||||
|         :param int modifiers: If it was shift/ctrl/alt | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Override this function to add your custom drawing code. | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def on_resize(self, width: float, height: float): | ||||
|         """ | ||||
|         Override this function to add custom code to be called any time the window | ||||
|         is resized. | ||||
|  | ||||
|         :param float width: New width | ||||
|         :param float height: New height | ||||
|         """ | ||||
|         original_viewport = self.get_viewport() | ||||
|  | ||||
|         # unscaled_viewport = self.get_viewport_size() | ||||
|         # scaling = unscaled_viewport[0] / width | ||||
|  | ||||
|         self.set_viewport(original_viewport[0], | ||||
|                           original_viewport[0] + width, | ||||
|                           original_viewport[2], | ||||
|                           original_viewport[2] + height) | ||||
|  | ||||
|     def set_min_size(self, width: float, height: float): | ||||
|         """ Wrap the Pyglet window call to set minimum size | ||||
|  | ||||
|         :param float width: width in pixels. | ||||
|         :param float height: height in pixels. | ||||
|         """ | ||||
|  | ||||
|         if self._resizable: | ||||
|             super().set_minimum_size(width, height) | ||||
|         else: | ||||
|             raise ValueError('Cannot set min size on non-resizable window') | ||||
|  | ||||
|     def set_max_size(self, width: float, height: float): | ||||
|         """ Wrap the Pyglet window call to set maximum size | ||||
|  | ||||
|         :param float width: width in pixels. | ||||
|         :param float height: height in pixels. | ||||
|         :Raises ValueError: | ||||
|  | ||||
|         """ | ||||
|  | ||||
|         if self._resizable: | ||||
|             super().set_maximum_size(width, height) | ||||
|         else: | ||||
|             raise ValueError('Cannot set max size on non-resizable window') | ||||
|  | ||||
|     def set_size(self, width: float, height: float): | ||||
|         """ | ||||
|         Ignore the resizable flag and set the size | ||||
|  | ||||
|         :param float width: | ||||
|         :param float height: | ||||
|         """ | ||||
|  | ||||
|         super().set_size(width, height) | ||||
|  | ||||
|     def get_size(self) -> Tuple[int, int]: | ||||
|         """ | ||||
|         Get the size of the window. | ||||
|  | ||||
|         :returns: (width, height) | ||||
|         """ | ||||
|  | ||||
|         return super().get_size() | ||||
|  | ||||
|     def get_location(self) -> Tuple[int, int]: | ||||
|         """ | ||||
|         Return the X/Y coordinates of the window | ||||
|  | ||||
|         :returns: x, y of window location | ||||
|         """ | ||||
|  | ||||
|         return super().get_location() | ||||
|  | ||||
|     def set_visible(self, visible=True): | ||||
|         """ | ||||
|         Set if the window is visible or not. Normally, a program's window is visible. | ||||
|  | ||||
|         :param bool visible: | ||||
|         """ | ||||
|         super().set_visible(visible) | ||||
|  | ||||
|     def set_viewport(self, left: Number, right: Number, bottom: Number, top: Number): | ||||
|         """ | ||||
|         Set the viewport. (What coordinates we can see. | ||||
|         Used to scale and/or scroll the screen.) | ||||
|  | ||||
|         :param Number left: | ||||
|         :param Number right: | ||||
|         :param Number bottom: | ||||
|         :param Number top: | ||||
|         """ | ||||
|         set_viewport(left, right, bottom, top) | ||||
|  | ||||
|     def get_viewport(self) -> (float, float, float, float): | ||||
|         """ Get the viewport. (What coordinates we can see.) """ | ||||
|         return get_viewport() | ||||
|  | ||||
|     def test(self, frames: int = 10): | ||||
|         """ | ||||
|         Used by unit test cases. Runs the event loop a few times and stops. | ||||
|  | ||||
|         :param int frames: | ||||
|         """ | ||||
|         for i in range(frames): | ||||
|             self.switch_to() | ||||
|             self.dispatch_events() | ||||
|             self.dispatch_event('on_draw') | ||||
|             self.flip() | ||||
|             self.update(1/60) | ||||
|  | ||||
|     def show_view(self, new_view: 'View'): | ||||
|         if not isinstance(new_view, View): | ||||
|             raise ValueError("Must pass an arcade.View object to " | ||||
|                              "Window.show_view()") | ||||
|  | ||||
|         # Store the Window that is showing the "new_view" View. | ||||
|         if new_view.window is None: | ||||
|             new_view.window = self | ||||
|         elif new_view.window != self: | ||||
|             raise RuntimeError("You are attempting to pass the same view " | ||||
|                                "object between multiple windows. A single " | ||||
|                                "view object can only be used in one window.") | ||||
|  | ||||
|         # remove previously shown view's handlers | ||||
|         if self.current_view is not None: | ||||
|             self.remove_handlers(self.current_view) | ||||
|  | ||||
|         # push new view's handlers | ||||
|         self.current_view = new_view | ||||
|         self.push_handlers(self.current_view) | ||||
|         self.current_view.on_show() | ||||
|  | ||||
|         # Note: After the View has been pushed onto pyglet's stack of event handlers (via push_handlers()), pyglet | ||||
|         # will still call the Window's event handlers. (See pyglet's EventDispatcher.dispatch_event() implementation | ||||
|         # for details) | ||||
|  | ||||
|     def _create(self): | ||||
|         super()._create() | ||||
|  | ||||
|     def _recreate(self, changes): | ||||
|         super()._recreate(changes) | ||||
|  | ||||
|     def flip(self): | ||||
|         super().flip() | ||||
|  | ||||
|     def switch_to(self): | ||||
|         super().switch_to() | ||||
|  | ||||
|     def set_caption(self, caption): | ||||
|         super().set_caption(caption) | ||||
|  | ||||
|     def set_minimum_size(self, width, height): | ||||
|         super().set_minimum_size(width, height) | ||||
|  | ||||
|     def set_maximum_size(self, width, height): | ||||
|         super().set_maxiumum_size(width, height) | ||||
|  | ||||
|     def set_location(self, x, y): | ||||
|         super().set_location(x, y) | ||||
|  | ||||
|     def activate(self): | ||||
|         super().activate() | ||||
|  | ||||
|     def minimize(self): | ||||
|         super().minimize() | ||||
|  | ||||
|     def maximize(self): | ||||
|         super().maximize() | ||||
|  | ||||
|     def set_vsync(self, vsync): | ||||
|         super().set_vsync(vsync) | ||||
|  | ||||
|     def set_mouse_platform_visible(self, platform_visible=None): | ||||
|         super().set_mouse_platform_visible(platform_visible) | ||||
|  | ||||
|     def set_exclusive_mouse(self, exclusive=True): | ||||
|         super().set_exclusive_mouse(exclusive) | ||||
|  | ||||
|     def set_exclusive_keyboard(self, exclusive=True): | ||||
|         super().set_exclusive_keyboard(exclusive) | ||||
|  | ||||
|     def get_system_mouse_cursor(self, name): | ||||
|         super().get_system_mouse_cursor(name) | ||||
|  | ||||
|     def dispatch_events(self): | ||||
|         super().dispatch_events() | ||||
|  | ||||
|  | ||||
| def open_window(width: Number, height: Number, window_title: str, resizable: bool = False, | ||||
|                 antialiasing: bool = True) -> Window: | ||||
|     """ | ||||
|     This function opens a window. For ease-of-use we assume there will only be one window, and the | ||||
|     programmer does not need to keep a handle to the window. This isn't the best architecture, because | ||||
|     the window handle is stored in a global, but it makes things easier for programmers if they don't | ||||
|     have to track a window pointer. | ||||
|  | ||||
|     :param Number width: Width of the window. | ||||
|     :param Number height: Height of the window. | ||||
|     :param str window_title: Title of the window. | ||||
|     :param bool resizable: Whether the window can be user-resizable. | ||||
|     :param bool antialiasing: Smooth the graphics? | ||||
|  | ||||
|     :returns: Handle to window | ||||
|     :rtype arcade.Window: | ||||
|     """ | ||||
|  | ||||
|     global _window | ||||
|     _window = Window(width, height, window_title, resizable, update_rate=None, | ||||
|                      antialiasing=antialiasing) | ||||
|     return _window | ||||
|  | ||||
|  | ||||
| class View: | ||||
|     """ | ||||
|     TODO:Thoughts: | ||||
|     - is there a need for a close()/on_close() method? | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         self.window = None | ||||
|  | ||||
|     def update(self, delta_time: float): | ||||
|         """To be overridden""" | ||||
|         pass | ||||
|  | ||||
|     def on_update(self, delta_time: float): | ||||
|         """To be overridden""" | ||||
|         pass | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """Called when this view should draw""" | ||||
|         pass | ||||
|  | ||||
|     def on_show(self): | ||||
|         """Called when this view is shown""" | ||||
|         pass | ||||
							
								
								
									
										13
									
								
								arcade/arcade_types.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,13 @@ | ||||
| """ | ||||
| Module specifying data custom types used for type hinting. | ||||
| """ | ||||
| from typing import Tuple | ||||
| from typing import List | ||||
| from typing import Union | ||||
|  | ||||
| RGB = Union[Tuple[int, int, int], List[int]] | ||||
| RGBA = Union[Tuple[int, int, int, int], List[int]] | ||||
| Color = Union[RGB, RGBA] | ||||
| Point = Union[Tuple[float, float], List[float]] | ||||
| Vector = Point | ||||
| PointList = Union[Tuple[Point, ...], List[Point]] | ||||
							
								
								
									
										793
									
								
								arcade/buffered_draw_commands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,793 @@ | ||||
| """ | ||||
| Drawing commands that use vertex buffer objects (VBOs). | ||||
|  | ||||
| This module contains commands for basic graphics drawing commands, | ||||
| but uses Vertex Buffer Objects. This keeps the vertices loaded on | ||||
| the graphics card for much faster render times. | ||||
| """ | ||||
|  | ||||
| import math | ||||
| import itertools | ||||
| from collections import defaultdict | ||||
| import pyglet.gl as gl | ||||
| import numpy as np | ||||
|  | ||||
| from typing import Iterable | ||||
| from typing import List | ||||
| from typing import TypeVar | ||||
| from typing import Generic | ||||
|  | ||||
| from arcade.arcade_types import Color | ||||
| from arcade.draw_commands import rotate_point | ||||
| from arcade.arcade_types import PointList | ||||
| from arcade.draw_commands import get_four_byte_color | ||||
| from arcade.draw_commands import get_projection | ||||
| from arcade.draw_commands import _get_points_for_thick_line | ||||
| from arcade import shader | ||||
|  | ||||
|  | ||||
| class VertexBuffer: | ||||
|     """ | ||||
|     This class represents a `vertex buffer object`_ for internal library use. Clients | ||||
|     of the library probably don't need to use this. | ||||
|  | ||||
|     Attributes: | ||||
|         :vbo_id: ID of the vertex buffer as assigned by OpenGL | ||||
|         :size: | ||||
|         :width: | ||||
|         :height: | ||||
|         :color: | ||||
|  | ||||
|  | ||||
|     .. _vertex buffer object: | ||||
|        https://en.wikipedia.org/wiki/Vertex_Buffer_Object | ||||
|  | ||||
|     """ | ||||
|     def __init__(self, vbo_vertex_id: gl.GLuint, size: float, draw_mode: int, vbo_color_id: gl.GLuint = None): | ||||
|         self.vbo_vertex_id = vbo_vertex_id | ||||
|         self.vbo_color_id = vbo_color_id | ||||
|         self.size = size | ||||
|         self.draw_mode = draw_mode | ||||
|         self.color = None | ||||
|         self.line_width = 0 | ||||
|  | ||||
|  | ||||
| class Shape: | ||||
|     def __init__(self): | ||||
|         self.vao = None | ||||
|         self.vbo = None | ||||
|         self.program = None | ||||
|         self.mode = None | ||||
|         self.line_width = 1 | ||||
|  | ||||
|     def draw(self): | ||||
|         # program['Projection'].write(get_projection().tobytes()) | ||||
|  | ||||
|         with self.vao: | ||||
|             assert(self.line_width == 1) | ||||
|             gl.glLineWidth(self.line_width) | ||||
|  | ||||
|             gl.glEnable(gl.GL_BLEND) | ||||
|             gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) | ||||
|             gl.glEnable(gl.GL_LINE_SMOOTH) | ||||
|             gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST) | ||||
|             gl.glHint(gl.GL_POLYGON_SMOOTH_HINT, gl.GL_NICEST) | ||||
|             gl.glEnable(gl.GL_PRIMITIVE_RESTART) | ||||
|             gl.glPrimitiveRestartIndex(2 ** 32 - 1) | ||||
|  | ||||
|             self.vao.render(mode=self.mode) | ||||
|  | ||||
|  | ||||
| def create_line(start_x: float, start_y: float, end_x: float, end_y: float, | ||||
|                 color: Color, line_width: float = 1) -> Shape: | ||||
|     """ | ||||
|     Create a line to be rendered later. This works faster than draw_line because | ||||
|     the vertexes are only loaded to the graphics card once, rather than each frame. | ||||
|  | ||||
|     :param float start_x: | ||||
|     :param float start_y: | ||||
|     :param float end_x: | ||||
|     :param float end_y: | ||||
|     :param Color color: | ||||
|     :param float line_width: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     points = _get_points_for_thick_line(start_x, start_y, end_x, end_y, line_width) | ||||
|     color_list = [color, color, color, color] | ||||
|     triangle_point_list = points[1], points[0], points[2], points[3] | ||||
|     shape = create_triangles_filled_with_colors(triangle_point_list, color_list) | ||||
|     return shape | ||||
|  | ||||
|  | ||||
| def create_line_generic_with_colors(point_list: PointList, | ||||
|                                     color_list: Iterable[Color], | ||||
|                                     shape_mode: int, | ||||
|                                     line_width: float = 1) -> Shape: | ||||
|     """ | ||||
|     This function is used by ``create_line_strip`` and ``create_line_loop``, | ||||
|     just changing the OpenGL type for the line drawing. | ||||
|  | ||||
|     :param PointList point_list: | ||||
|     :param Iterable[Color] color_list: | ||||
|     :param float shape_mode: | ||||
|     :param float line_width: | ||||
|  | ||||
|     :Returns Shape: | ||||
|     """ | ||||
|     program = shader.program( | ||||
|         vertex_shader=''' | ||||
|             #version 330 | ||||
|             uniform mat4 Projection; | ||||
|             in vec2 in_vert; | ||||
|             in vec4 in_color; | ||||
|             out vec4 v_color; | ||||
|             void main() { | ||||
|                gl_Position = Projection * vec4(in_vert, 0.0, 1.0); | ||||
|                v_color = in_color; | ||||
|             } | ||||
|         ''', | ||||
|         fragment_shader=''' | ||||
|             #version 330 | ||||
|             in vec4 v_color; | ||||
|             out vec4 f_color; | ||||
|             void main() { | ||||
|                 f_color = v_color; | ||||
|             } | ||||
|         ''', | ||||
|     ) | ||||
|  | ||||
|     buffer_type = np.dtype([('vertex', '2f4'), ('color', '4B')]) | ||||
|     data = np.zeros(len(point_list), dtype=buffer_type) | ||||
|     data['vertex'] = point_list | ||||
|     data['color'] = [get_four_byte_color(color) for color in color_list] | ||||
|  | ||||
|     vbo = shader.buffer(data.tobytes()) | ||||
|     vao_content = [ | ||||
|         shader.BufferDescription( | ||||
|             vbo, | ||||
|             '2f 4B', | ||||
|             ('in_vert', 'in_color'), | ||||
|             normalized=['in_color'] | ||||
|         ) | ||||
|     ] | ||||
|  | ||||
|     vao = shader.vertex_array(program, vao_content) | ||||
|     with vao: | ||||
|         program['Projection'] = get_projection().flatten() | ||||
|  | ||||
|     shape = Shape() | ||||
|     shape.vao = vao | ||||
|     shape.vbo = vbo | ||||
|     shape.program = program | ||||
|     shape.mode = shape_mode | ||||
|     shape.line_width = line_width | ||||
|  | ||||
|     return shape | ||||
|  | ||||
|  | ||||
| def create_line_generic(point_list: PointList, | ||||
|                         color: Color, | ||||
|                         shape_mode: int, line_width: float = 1) -> Shape: | ||||
|     """ | ||||
|     This function is used by ``create_line_strip`` and ``create_line_loop``, | ||||
|     just changing the OpenGL type for the line drawing. | ||||
|     """ | ||||
|     colors = [get_four_byte_color(color)] * len(point_list) | ||||
|     shape = create_line_generic_with_colors( | ||||
|         point_list, | ||||
|         colors, | ||||
|         shape_mode, | ||||
|         line_width) | ||||
|  | ||||
|     return shape | ||||
|  | ||||
|  | ||||
| def create_line_strip(point_list: PointList, | ||||
|                       color: Color, line_width: float = 1): | ||||
|     """ | ||||
|     Create a multi-point line to be rendered later. This works faster than draw_line because | ||||
|     the vertexes are only loaded to the graphics card once, rather than each frame. | ||||
|  | ||||
|     :param PointList point_list: | ||||
|     :param Color color: | ||||
|     :param PointList line_width: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|     if line_width == 1: | ||||
|         return create_line_generic(point_list, color, gl.GL_LINE_STRIP, line_width) | ||||
|     else: | ||||
|         triangle_point_list = [] | ||||
|         new_color_list = [] | ||||
|         for i in range(1, len(point_list)): | ||||
|             start_x = point_list[i - 1][0] | ||||
|             start_y = point_list[i - 1][1] | ||||
|             end_x = point_list[i][0] | ||||
|             end_y = point_list[i][1] | ||||
|             color1 = color | ||||
|             color2 = color | ||||
|             points = _get_points_for_thick_line(start_x, start_y, end_x, end_y, line_width) | ||||
|             new_color_list += color1, color2, color1, color2 | ||||
|             triangle_point_list += points[1], points[0], points[2], points[3] | ||||
|  | ||||
|             shape = create_triangles_filled_with_colors(triangle_point_list, new_color_list) | ||||
|             return shape | ||||
|  | ||||
|  | ||||
| def create_line_loop(point_list: PointList, | ||||
|                      color: Color, line_width: float = 1): | ||||
|     """ | ||||
|     Create a multi-point line loop to be rendered later. This works faster than draw_line because | ||||
|     the vertexes are only loaded to the graphics card once, rather than each frame. | ||||
|  | ||||
|     :param PointList point_list: | ||||
|     :param Color color: | ||||
|     :param float line_width: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|     point_list = list(point_list) + [point_list[0]] | ||||
|     return create_line_generic(point_list, color, gl.GL_LINE_STRIP, line_width) | ||||
|  | ||||
|  | ||||
| def create_lines(point_list: PointList, | ||||
|                  color: Color, line_width: float = 1): | ||||
|     """ | ||||
|     Create a multi-point line loop to be rendered later. This works faster than draw_line because | ||||
|     the vertexes are only loaded to the graphics card once, rather than each frame. | ||||
|  | ||||
|     :param PointList point_list: | ||||
|     :param Color color: | ||||
|     :param float line_width: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|     return create_line_generic(point_list, color, gl.GL_LINES, line_width) | ||||
|  | ||||
|  | ||||
| def create_lines_with_colors(point_list: PointList, | ||||
|                              color_list: List[Color], | ||||
|                              line_width: float = 1): | ||||
|  | ||||
|     if line_width == 1: | ||||
|         return create_line_generic_with_colors(point_list, color_list, gl.GL_LINES, line_width) | ||||
|     else: | ||||
|  | ||||
|         triangle_point_list = [] | ||||
|         new_color_list = [] | ||||
|         for i in range(1, len(point_list), 2): | ||||
|             start_x = point_list[i-1][0] | ||||
|             start_y = point_list[i-1][1] | ||||
|             end_x = point_list[i][0] | ||||
|             end_y = point_list[i][1] | ||||
|             color1 = color_list[i-1] | ||||
|             color2 = color_list[i] | ||||
|             points = _get_points_for_thick_line(start_x, start_y, end_x, end_y, line_width) | ||||
|             new_color_list += color1, color1, color2, color2 | ||||
|             triangle_point_list += points[1], points[0], points[2], points[3] | ||||
|  | ||||
|             shape = create_triangles_filled_with_colors(triangle_point_list, new_color_list) | ||||
|             return shape | ||||
|  | ||||
|  | ||||
| def create_polygon(point_list: PointList, | ||||
|                    color: Color): | ||||
|     """ | ||||
|     Draw a convex polygon. This will NOT draw a concave polygon. | ||||
|     Because of this, you might not want to use this function. | ||||
|  | ||||
|     :param PointList point_list: | ||||
|     :param color: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|     # We assume points were given in order, either clockwise or counter clockwise. | ||||
|     # Polygon is assumed to be monotone. | ||||
|     # To fill the polygon, we start by one vertex, and we chain triangle strips | ||||
|     # alternating with vertices to the left and vertices to the right of the | ||||
|     # initial vertex. | ||||
|     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] | ||||
|     return create_line_generic(point_list, color, gl.GL_TRIANGLE_STRIP, 1) | ||||
|  | ||||
|  | ||||
| def create_rectangle_filled(center_x: float, center_y: float, width: float, | ||||
|                             height: float, color: Color, | ||||
|                             tilt_angle: float = 0) -> Shape: | ||||
|     """ | ||||
|     Create a filled rectangle. | ||||
|  | ||||
|     :param float center_x: | ||||
|     :param float center_y: | ||||
|     :param float width: | ||||
|     :param float height: | ||||
|     :param Color color: | ||||
|     :param float tilt_angle: | ||||
|  | ||||
|     :Returns Shape: | ||||
|  | ||||
|     """ | ||||
|     return create_rectangle(center_x, center_y, width, height, | ||||
|                             color, tilt_angle=tilt_angle) | ||||
|  | ||||
|  | ||||
| def create_rectangle_outline(center_x: float, center_y: float, width: float, | ||||
|                              height: float, color: Color, | ||||
|                              border_width: float = 1, tilt_angle: float = 0) -> Shape: | ||||
|     """ | ||||
|     Create a rectangle outline. | ||||
|  | ||||
|     Args: | ||||
|         center_x: | ||||
|         center_y: | ||||
|         width: | ||||
|         height: | ||||
|         color: | ||||
|         border_width: | ||||
|         tilt_angle: | ||||
|  | ||||
|     Returns: | ||||
|  | ||||
|     """ | ||||
|     return create_rectangle(center_x, center_y, width, height, | ||||
|                             color, border_width, tilt_angle, filled=False) | ||||
|  | ||||
|  | ||||
| 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_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 = 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 = [] | ||||
|             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 create_rectangle_filled_with_colors(point_list, color_list) -> Shape: | ||||
|     """ | ||||
|     This function creates one rectangle/quad using a vertex buffer object. | ||||
|     Creating the rectangles, and then later drawing it with ``render`` | ||||
|     is faster than calling ``draw_rectangle``. | ||||
|     """ | ||||
|  | ||||
|     shape_mode = gl.GL_TRIANGLE_STRIP | ||||
|     new_point_list = [point_list[0], point_list[1], point_list[3], point_list[2]] | ||||
|     new_color_list = [color_list[0], color_list[1], color_list[3], color_list[2]] | ||||
|     return create_line_generic_with_colors(new_point_list, new_color_list, shape_mode) | ||||
|  | ||||
|  | ||||
| def create_rectangles_filled_with_colors(point_list, color_list) -> Shape: | ||||
|     """ | ||||
|     This function creates multiple rectangle/quads using a vertex buffer object. | ||||
|     Creating the rectangles, and then later drawing it with ``render`` | ||||
|     is faster than calling ``draw_rectangle``. | ||||
|     """ | ||||
|  | ||||
|     shape_mode = gl.GL_TRIANGLES | ||||
|     new_point_list = [] | ||||
|     new_color_list = [] | ||||
|     for i in range(0, len(point_list), 4): | ||||
|         new_point_list += [point_list[0 + i], point_list[1 + i], point_list[3 + i]] | ||||
|         new_point_list += [point_list[1 + i], point_list[3 + i], point_list[2 + i]] | ||||
|  | ||||
|         new_color_list += [color_list[0 + i], color_list[1 + i], color_list[3 + i]] | ||||
|         new_color_list += [color_list[1 + i], color_list[3 + i], color_list[2 + i]] | ||||
|  | ||||
|     return create_line_generic_with_colors(new_point_list, new_color_list, shape_mode) | ||||
|  | ||||
|  | ||||
| def create_triangles_filled_with_colors(point_list, color_list) -> Shape: | ||||
|     """ | ||||
|     This function creates multiple rectangle/quads using a vertex buffer object. | ||||
|     Creating the rectangles, and then later drawing it with ``render`` | ||||
|     is faster than calling ``draw_rectangle``. | ||||
|     """ | ||||
|  | ||||
|     shape_mode = gl.GL_TRIANGLE_STRIP | ||||
|     return create_line_generic_with_colors(point_list, color_list, shape_mode) | ||||
|  | ||||
|  | ||||
| def create_ellipse_filled(center_x: float, center_y: float, | ||||
|                           width: float, height: float, color: Color, | ||||
|                           tilt_angle: float = 0, num_segments: int = 128) -> Shape: | ||||
|     """ | ||||
|     Create a filled ellipse. Or circle if you use the same width and height. | ||||
|     """ | ||||
|  | ||||
|     border_width = 1 | ||||
|     return create_ellipse(center_x, center_y, width, height, color, | ||||
|                           border_width, tilt_angle, num_segments, filled=True) | ||||
|  | ||||
|  | ||||
| def create_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) -> Shape: | ||||
|     """ | ||||
|     Create an outline of an ellipse. | ||||
|     """ | ||||
|  | ||||
|     return create_ellipse(center_x, center_y, width, height, color, | ||||
|                           border_width, tilt_angle, num_segments, filled=False) | ||||
|  | ||||
|  | ||||
| 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 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) | ||||
|  | ||||
|  | ||||
| T = TypeVar('T', bound=Shape) | ||||
|  | ||||
|  | ||||
| class ShapeElementList(Generic[T]): | ||||
|     """ | ||||
|     A program can put multiple drawing primitives in a ShapeElementList, and then | ||||
|     move and draw them as one. Do this when you want to create a more complex object | ||||
|     out of simpler primitives. This also speeds rendering as all objects are drawn | ||||
|     in one operation. | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         """ | ||||
|         Initialize the sprite list | ||||
|         """ | ||||
|         # List of sprites in the sprite list | ||||
|         self.shape_list = [] | ||||
|         self.change_x = 0 | ||||
|         self.change_y = 0 | ||||
|         self._center_x = 0 | ||||
|         self._center_y = 0 | ||||
|         self._angle = 0 | ||||
|         self.program = shader.program( | ||||
|             vertex_shader=''' | ||||
|                 #version 330 | ||||
|                 uniform mat4 Projection; | ||||
|                 uniform vec2 Position; | ||||
|                 uniform float Angle; | ||||
|  | ||||
|                 in vec2 in_vert; | ||||
|                 in vec4 in_color; | ||||
|  | ||||
|                 out vec4 v_color; | ||||
|                 void main() { | ||||
|                     float angle = radians(Angle); | ||||
|                     mat2 rotate = mat2( | ||||
|                         cos(angle), sin(angle), | ||||
|                         -sin(angle), cos(angle) | ||||
|                     ); | ||||
|                    gl_Position = Projection * vec4(Position + (rotate * in_vert), 0.0, 1.0); | ||||
|                    v_color = in_color; | ||||
|                 } | ||||
|             ''', | ||||
|             fragment_shader=''' | ||||
|                 #version 330 | ||||
|                 in vec4 v_color; | ||||
|                 out vec4 f_color; | ||||
|                 void main() { | ||||
|                     f_color = v_color; | ||||
|                 } | ||||
|             ''', | ||||
|         ) | ||||
|         # Could do much better using just one vbo and glDrawElementsBaseVertex | ||||
|         self.batches = defaultdict(_Batch) | ||||
|         self.dirties = set() | ||||
|  | ||||
|     def append(self, item: T): | ||||
|         """ | ||||
|         Add a new shape to the list. | ||||
|         """ | ||||
|         self.shape_list.append(item) | ||||
|         group = (item.mode, item.line_width) | ||||
|         self.batches[group].items.append(item) | ||||
|         self.dirties.add(group) | ||||
|  | ||||
|     def remove(self, item: T): | ||||
|         """ | ||||
|         Remove a specific shape from the list. | ||||
|         """ | ||||
|         self.shape_list.remove(item) | ||||
|         group = (item.mode, item.line_width) | ||||
|         self.batches[group].items.remove(item) | ||||
|         self.dirties.add(group) | ||||
|  | ||||
|     def _refresh_shape(self, group): | ||||
|         # Create a buffer large enough to hold all the shapes buffers | ||||
|         batch = self.batches[group] | ||||
|         total_vbo_bytes = sum(s.vbo.size for s in batch.items) | ||||
|         vbo = shader.Buffer.create_with_size(total_vbo_bytes) | ||||
|         offset = 0 | ||||
|         gl.glBindBuffer(gl.GL_COPY_WRITE_BUFFER, vbo.buffer_id) | ||||
|         # Copy all the shapes buffer in our own vbo | ||||
|         for shape in batch.items: | ||||
|             gl.glBindBuffer(gl.GL_COPY_READ_BUFFER, shape.vbo.buffer_id) | ||||
|             gl.glCopyBufferSubData( | ||||
|                 gl.GL_COPY_READ_BUFFER, | ||||
|                 gl.GL_COPY_WRITE_BUFFER, | ||||
|                 gl.GLintptr(0), | ||||
|                 gl.GLintptr(offset), | ||||
|                 shape.vbo.size) | ||||
|             offset += shape.vbo.size | ||||
|  | ||||
|         # Create an index buffer object. It should count starting from 0. We need to | ||||
|         # use a reset_idx to indicate that a new shape will start. | ||||
|         reset_idx = 2 ** 32 - 1 | ||||
|         indices = [] | ||||
|         counter = itertools.count() | ||||
|         for shape in batch.items: | ||||
|             indices.extend(itertools.islice(counter, shape.vao.num_vertices)) | ||||
|             indices.append(reset_idx) | ||||
|         del indices[-1] | ||||
|         indices = np.array(indices) | ||||
|         ibo = shader.Buffer(indices.astype('i4').tobytes()) | ||||
|  | ||||
|         vao_content = [ | ||||
|             shader.BufferDescription( | ||||
|                 vbo, | ||||
|                 '2f 4B', | ||||
|                 ('in_vert', 'in_color'), | ||||
|                 normalized=['in_color'] | ||||
|             ) | ||||
|         ] | ||||
|         vao = shader.vertex_array(self.program, vao_content, ibo) | ||||
|         with self.program: | ||||
|             self.program['Projection'] = get_projection().flatten() | ||||
|             self.program['Position'] = [self.center_x, self.center_y] | ||||
|             self.program['Angle'] = self.angle | ||||
|  | ||||
|         batch.shape.vao = vao | ||||
|         batch.shape.vbo = vbo | ||||
|         batch.shape.ibo = ibo | ||||
|         batch.shape.program = self.program | ||||
|         mode, line_width = group | ||||
|         batch.shape.mode = mode | ||||
|         batch.shape.line_width = line_width | ||||
|  | ||||
|     def move(self, change_x: float, change_y: float): | ||||
|         """ | ||||
|         Move all the shapes ion the list | ||||
|         :param change_x: Amount to move on the x axis | ||||
|         :param change_y: Amount to move on the y axis | ||||
|         """ | ||||
|         self.center_x += change_x | ||||
|         self.center_y += change_y | ||||
|  | ||||
|     def __len__(self) -> int: | ||||
|         """ Return the length of the sprite list. """ | ||||
|         return len(self.shape_list) | ||||
|  | ||||
|     def __iter__(self) -> Iterable[T]: | ||||
|         """ Return an iterable object of sprites. """ | ||||
|         return iter(self.shape_list) | ||||
|  | ||||
|     def __getitem__(self, i): | ||||
|         return self.shape_list[i] | ||||
|  | ||||
|     def draw(self): | ||||
|         """ | ||||
|         Draw everything in the list. | ||||
|         """ | ||||
|         for group in self.dirties: | ||||
|             self._refresh_shape(group) | ||||
|         self.dirties.clear() | ||||
|         for batch in self.batches.values(): | ||||
|             batch.shape.draw() | ||||
|  | ||||
|     def _get_center_x(self) -> float: | ||||
|         """Get the center x coordinate of the ShapeElementList.""" | ||||
|         return self._center_x | ||||
|  | ||||
|     def _set_center_x(self, value: float): | ||||
|         """Set the center x coordinate of the ShapeElementList.""" | ||||
|         self._center_x = value | ||||
|         with self.program: | ||||
|             self.program['Position'] = [self._center_x, self._center_y] | ||||
|  | ||||
|     center_x = property(_get_center_x, _set_center_x) | ||||
|  | ||||
|     def _get_center_y(self) -> float: | ||||
|         """Get the center y coordinate of the ShapeElementList.""" | ||||
|         return self._center_y | ||||
|  | ||||
|     def _set_center_y(self, value: float): | ||||
|         """Set the center y coordinate of the ShapeElementList.""" | ||||
|         self._center_y = value | ||||
|         with self.program: | ||||
|             self.program['Position'] = [self._center_x, self._center_y] | ||||
|  | ||||
|     center_y = property(_get_center_y, _set_center_y) | ||||
|  | ||||
|     def _get_angle(self) -> float: | ||||
|         """Get the angle of the ShapeElementList in degrees.""" | ||||
|         return self._angle | ||||
|  | ||||
|     def _set_angle(self, value: float): | ||||
|         """Set the angle of the ShapeElementList in degrees.""" | ||||
|         self._angle = value | ||||
|         with self.program: | ||||
|             self.program['Angle'] = self._angle | ||||
|  | ||||
|     angle = property(_get_angle, _set_angle) | ||||
|  | ||||
|  | ||||
| class _Batch(Generic[T]): | ||||
|     def __init__(self): | ||||
|         self.shape = Shape() | ||||
|         self.items = [] | ||||
							
								
								
									
										1006
									
								
								arcade/color/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										152
									
								
								arcade/csscolor/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,152 @@ | ||||
| """ | ||||
| This module pre-defines colors as defined by the W3C CSS standard: | ||||
| https://www.w3.org/TR/2018/PR-css-color-3-20180315/ | ||||
| """ | ||||
|  | ||||
| ALICE_BLUE = (240, 248, 255) | ||||
| ANTIQUE_WHITE = (250, 235, 215) | ||||
| AQUA = (0, 255, 255) | ||||
| AQUAMARINE = (127, 255, 212) | ||||
| AZURE = (240, 255, 255) | ||||
| BEIGE = (245, 245, 220) | ||||
| BISQUE = (255, 228, 196) | ||||
| BLACK = (0, 0, 0) | ||||
| BLANCHED_ALMOND = (255, 235, 205) | ||||
| BLUE = (0, 0, 255) | ||||
| BLUE_VIOLET = (138, 43, 226) | ||||
| BROWN = (165, 42, 42) | ||||
| BURLYWOOD = (222, 184, 135) | ||||
| CADET_BLUE = (95, 158, 160) | ||||
| CHARTREUSE = (127, 255, 0) | ||||
| CHOCOLATE = (210, 105, 30) | ||||
| CORAL = (255, 127, 80) | ||||
| CORNFLOWER_BLUE = (100, 149, 237) | ||||
| CORNSILK = (255, 248, 220) | ||||
| CRIMSON = (220, 20, 60) | ||||
| CYAN = (0, 255, 255) | ||||
| DARK_BLUE = (0, 0, 139) | ||||
| DARK_CYAN = (0, 139, 139) | ||||
| DARK_GOLDENROD = (184, 134, 11) | ||||
| DARK_GRAY = (169, 169, 169) | ||||
| DARK_GREEN = (0, 100, 0) | ||||
| DARK_GREY = (169, 169, 169) | ||||
| DARK_KHAKI = (189, 183, 107) | ||||
| DARK_MAGENTA = (139, 0, 139) | ||||
| DARK_OLIVE_GREEN = (85, 107, 47) | ||||
| DARK_ORANGE = (255, 140, 0) | ||||
| DARK_ORCHID = (153, 50, 204) | ||||
| DARK_RED = (139, 0, 0) | ||||
| DARK_SALMON = (233, 150, 122) | ||||
| DARK_SEA_GREEN = (143, 188, 143) | ||||
| DARK_SLATE_BLUE = (72, 61, 139) | ||||
| DARK_SLATE_GRAY = (47, 79, 79) | ||||
| DARK_SLATE_GREY = (47, 79, 79) | ||||
| DARK_TURQUOISE = (0, 206, 209) | ||||
| DARK_VIOLET = (148, 0, 211) | ||||
| DEEP_PINK = (255, 20, 147) | ||||
| DEEP_SKY_BLUE = (0, 191, 255) | ||||
| DIM_GRAY = (105, 105, 105) | ||||
| DIM_GREY = (105, 105, 105) | ||||
| DODGER_BLUE = (30, 144, 255) | ||||
| FIREBRICK = (178, 34, 34) | ||||
| FLORAL_WHITE = (255, 250, 240) | ||||
| FOREST_GREEN = (34, 139, 34) | ||||
| FUCHSIA = (255, 0, 255) | ||||
| GAINSBORO = (220, 220, 220) | ||||
| GHOST_WHITE = (248, 248, 255) | ||||
| GOLD = (255, 215, 0) | ||||
| GOLDENROD = (218, 165, 32) | ||||
| GRAY = (128, 128, 128) | ||||
| GREEN = (0, 128, 0) | ||||
| GREENYELLOW = (173, 255, 47) | ||||
| GREY = (128, 128, 128) | ||||
| HONEYDEW = (240, 255, 240) | ||||
| HOTPINK = (255, 105, 180) | ||||
| INDIANRED = (205, 92, 92) | ||||
| INDIGO = (75, 0, 130) | ||||
| IVORY = (255, 255, 240) | ||||
| KHAKI = (240, 230, 140) | ||||
| LAVENDER = (230, 230, 250) | ||||
| LAVENDER_BLUSH = (255, 240, 245) | ||||
| LAWNGREEN = (124, 252, 0) | ||||
| LEMON_CHIFFON = (255, 250, 205) | ||||
| LIGHT_BLUE = (173, 216, 230) | ||||
| LIGHT_CORAL = (240, 128, 128) | ||||
| LIGHT_CYAN = (224, 255, 255) | ||||
| LIGHT_GOLDENROD_YELLOW = (250, 250, 210) | ||||
| LIGHT_GRAY = (211, 211, 211) | ||||
| LIGHT_GREEN = (144, 238, 144) | ||||
| LIGHT_GREY = (211, 211, 211) | ||||
| LIGHT_PINK = (255, 182, 193) | ||||
| LIGHT_SALMON = (255, 160, 122) | ||||
| LIGHT_SEA_GREEN = (32, 178, 170) | ||||
| LIGHT_SKY_BLUE = (135, 206, 250) | ||||
| LIGHT_SLATE_GRAY = (119, 136, 153) | ||||
| LIGHT_SLATE_GREY = (119, 136, 153) | ||||
| LIGHT_STEEL_BLUE = (176, 196, 222) | ||||
| LIGHT_YELLOW = (255, 255, 224) | ||||
| LIME = (0, 255, 0) | ||||
| LIME_GREEN = (50, 205, 50) | ||||
| LINEN = (250, 240, 230) | ||||
| MAGENTA = (255, 0, 255) | ||||
| MAROON = (128, 0, 0) | ||||
| MEDIUM_AQUAMARINE = (102, 205, 170) | ||||
| MEDIUM_BLUE = (0, 0, 205) | ||||
| MEDIUM_ORCHID = (186, 85, 211) | ||||
| MEDIUM_PURPLE = (147, 112, 219) | ||||
| MEDIUM_SEA_GREEN = (60, 179, 113) | ||||
| MEDIUM_SLATE_BLUE = (123, 104, 238) | ||||
| MEDIUM_SPRING_GREEN = (0, 250, 154) | ||||
| MEDIUM_TURQUOISE = (72, 209, 204) | ||||
| MEDIUM_VIOLET_RED = (199, 21, 133) | ||||
| MIDNIGHT_BLUE = (25, 25, 112) | ||||
| MINT_CREAM = (245, 255, 250) | ||||
| MISTY_ROSE = (255, 228, 225) | ||||
| MOCCASIN = (255, 228, 181) | ||||
| NAVAJO_WHITE = (255, 222, 173) | ||||
| NAVY = (0, 0, 128) | ||||
| OLD_LACE = (253, 245, 230) | ||||
| OLIVE = (128, 128, 0) | ||||
| OLIVE_DRAB = (107, 142, 35) | ||||
| ORANGE = (255, 165, 0) | ||||
| ORANGE_RED = (255, 69, 0) | ||||
| ORCHID = (218, 112, 214) | ||||
| PALE_GOLDENROD = (238, 232, 170) | ||||
| PALE_GREEN = (152, 251, 152) | ||||
| PALE_TURQUOISE = (175, 238, 238) | ||||
| PALE_VIOLET_RED = (219, 112, 147) | ||||
| PAPAYA_WHIP = (255, 239, 213) | ||||
| PEACH_PUFF = (255, 218, 185) | ||||
| PERU = (205, 133, 63) | ||||
| PINK = (255, 192, 203) | ||||
| PLUM = (221, 160, 221) | ||||
| POWDER_BLUE = (176, 224, 230) | ||||
| PURPLE = (128, 0, 128) | ||||
| RED = (255, 0, 0) | ||||
| ROSY_BROWN = (188, 143, 143) | ||||
| ROYAL_BLUE = (65, 105, 225) | ||||
| SADDLE_BROWN = (139, 69, 19) | ||||
| SALMON = (250, 128, 114) | ||||
| SANDY_BROWN = (244, 164, 96) | ||||
| SEA_GREEN = (46, 139, 87) | ||||
| SEASHELL = (255, 245, 238) | ||||
| SIENNA = (160, 82, 45) | ||||
| SILVER = (192, 192, 192) | ||||
| SKY_BLUE = (135, 206, 235) | ||||
| SLATE_BLUE = (106, 90, 205) | ||||
| SLATE_GRAY = (112, 128, 144) | ||||
| SLATE_GREY = (112, 128, 144) | ||||
| SNOW = (255, 250, 250) | ||||
| SPRING_GREEN = (0, 255, 127) | ||||
| STEEL_BLUE = (70, 130, 180) | ||||
| TAN = (210, 180, 140) | ||||
| TEAL = (0, 128, 128) | ||||
| THISTLE = (216, 191, 216) | ||||
| TOMATO = (255, 99, 71) | ||||
| TURQUOISE = (64, 224, 208) | ||||
| VIOLET = (238, 130, 238) | ||||
| WHEAT = (245, 222, 179) | ||||
| WHITE = (255, 255, 255) | ||||
| WHITE_SMOKE = (245, 245, 245) | ||||
| YELLOW = (255, 255, 0) | ||||
| YELLOW_GREEN = (154, 205) | ||||
							
								
								
									
										1342
									
								
								arcade/draw_commands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										113
									
								
								arcade/earclip.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,113 @@ | ||||
| """ | ||||
|  | ||||
| from: https://github.com/linuxlewis/tripy/blob/master/tripy.py | ||||
| """ | ||||
|  | ||||
| from collections import namedtuple | ||||
|  | ||||
| Point = namedtuple('Point', ['x', 'y']) | ||||
|  | ||||
|  | ||||
| def earclip(polygon): | ||||
|     """ | ||||
|     Simple earclipping algorithm for a given polygon p. | ||||
|     polygon is expected to be an array of 2-tuples of the cartesian points of the polygon | ||||
|     For a polygon with n points it will return n-2 triangles. | ||||
|     The triangles are returned as an array of 3-tuples where each item in the tuple is a 2-tuple of the cartesian point. | ||||
|  | ||||
|     Implementation Reference: | ||||
|         - https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf | ||||
|     """ | ||||
|     ear_vertex = [] | ||||
|     triangles = [] | ||||
|  | ||||
|     polygon = [Point(*point) for point in polygon] | ||||
|  | ||||
|     if _is_clockwise(polygon): | ||||
|         polygon.reverse() | ||||
|  | ||||
|     point_count = len(polygon) | ||||
|     for i in range(point_count): | ||||
|         prev_index = i - 1 | ||||
|         prev_point = polygon[prev_index] | ||||
|         point = polygon[i] | ||||
|         next_index = (i + 1) % point_count | ||||
|         next_point = polygon[next_index] | ||||
|  | ||||
|         if _is_ear(prev_point, point, next_point, polygon): | ||||
|             ear_vertex.append(point) | ||||
|  | ||||
|     while ear_vertex and point_count >= 3: | ||||
|         ear = ear_vertex.pop(0) | ||||
|         i = polygon.index(ear) | ||||
|         prev_index = i - 1 | ||||
|         prev_point = polygon[prev_index] | ||||
|         next_index = (i + 1) % point_count | ||||
|         next_point = polygon[next_index] | ||||
|  | ||||
|         polygon.remove(ear) | ||||
|         point_count -= 1 | ||||
|         triangles.append(((prev_point.x, prev_point.y), (ear.x, ear.y), (next_point.x, next_point.y))) | ||||
|         if point_count > 3: | ||||
|             prev_prev_point = polygon[prev_index - 1] | ||||
|             next_next_index = (i + 1) % point_count | ||||
|             next_next_point = polygon[next_next_index] | ||||
|  | ||||
|             groups = [ | ||||
|                 (prev_prev_point, prev_point, next_point, polygon), | ||||
|                 (prev_point, next_point, next_next_point, polygon) | ||||
|             ] | ||||
|             for group in groups: | ||||
|                 p = group[1] | ||||
|                 if _is_ear(*group): | ||||
|                     if p not in ear_vertex: | ||||
|                         ear_vertex.append(p) | ||||
|                 elif p in ear_vertex: | ||||
|                     ear_vertex.remove(p) | ||||
|     return triangles | ||||
|  | ||||
|  | ||||
| def _is_clockwise(polygon): | ||||
|     s = 0 | ||||
|     polygon_count = len(polygon) | ||||
|     for i in range(polygon_count): | ||||
|         point = polygon[i] | ||||
|         point2 = polygon[(i + 1) % polygon_count] | ||||
|         s += (point2.x - point.x) * (point2.y + point.y) | ||||
|     return s > 0 | ||||
|  | ||||
|  | ||||
| def _is_convex(prev, point, next_point): | ||||
|     return _triangle_sum(prev.x, prev.y, point.x, point.y, next_point.x, next_point.y) < 0 | ||||
|  | ||||
|  | ||||
| def _is_ear(p1, p2, p3, polygon): | ||||
|     ear = _contains_no_points(p1, p2, p3, polygon) and \ | ||||
|           _is_convex(p1, p2, p3) and \ | ||||
|           _triangle_area(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y) > 0 | ||||
|     return ear | ||||
|  | ||||
|  | ||||
| def _contains_no_points(p1, p2, p3, polygon): | ||||
|     for pn in polygon: | ||||
|         if pn in (p1, p2, p3): | ||||
|             continue | ||||
|         elif _is_point_inside(pn, p1, p2, p3): | ||||
|             return False | ||||
|     return True | ||||
|  | ||||
|  | ||||
| def _is_point_inside(p, a, b, c): | ||||
|     area = _triangle_area(a.x, a.y, b.x, b.y, c.x, c.y) | ||||
|     area1 = _triangle_area(p.x, p.y, b.x, b.y, c.x, c.y) | ||||
|     area2 = _triangle_area(p.x, p.y, a.x, a.y, c.x, c.y) | ||||
|     area3 = _triangle_area(p.x, p.y, a.x, a.y, b.x, b.y) | ||||
|     return area == sum([area1, area2, area3]) | ||||
|  | ||||
|  | ||||
| def _triangle_area(x1, y1, x2, y2, x3, y3): | ||||
|     return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0) | ||||
|  | ||||
|  | ||||
| def _triangle_sum(x1, y1, x2, y2, x3, y3): | ||||
|     return x1 * (y3 - y2) + x2 * (y1 - y3) + x3 * (y2 - y1) | ||||
							
								
								
									
										179
									
								
								arcade/emitter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,179 @@ | ||||
| """ | ||||
| Emitter - Invisible object that determines when Particles are emitted, actually emits them, and manages them | ||||
| over their lifetime | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
| from arcade.particle import Particle | ||||
| from typing import Callable, cast | ||||
| from arcade.utils import _Vec2 | ||||
| from arcade.arcade_types import Point, Vector | ||||
|  | ||||
|  | ||||
| ########## | ||||
| class EmitController: | ||||
|     """Base class for how a client configure the rate at which an Emitter emits Particles | ||||
|  | ||||
|     Subclasses allow the client to control the rate and duration of emitting""" | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         raise NotImplemented("EmitterRate.how_many must be implemented") | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         raise NotImplemented("EmitterRate.is_complete must be implemented") | ||||
|  | ||||
|  | ||||
| class EmitBurst(EmitController): | ||||
|     """Used to configure an Emitter to emit particles in one burst""" | ||||
|     def __init__(self, count: int): | ||||
|         self._is_complete = False | ||||
|         self._count = count | ||||
|  | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         if not self._is_complete: | ||||
|             self._is_complete = True | ||||
|             return self._count | ||||
|         return 0 | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         return True | ||||
|  | ||||
|  | ||||
| class EmitMaintainCount(EmitController): | ||||
|     """Used to configure an Emitter so it emits particles so that the given count is always maintained""" | ||||
|     def __init__(self, particle_count: int): | ||||
|         self._target_count = particle_count | ||||
|  | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         return self._target_count - current_particle_count | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| class EmitInterval(EmitController): | ||||
|     """Base class used to configure an Emitter to have a constant rate of emitting. Will emit indefinitely.""" | ||||
|     def __init__(self, emit_interval: float): | ||||
|         self._emit_interval = emit_interval | ||||
|         self._carryover_time = 0.0 | ||||
|  | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         self._carryover_time += delta_time | ||||
|         emit_count = 0 | ||||
|         while self._carryover_time >= self._emit_interval: | ||||
|             self._carryover_time -= self._emit_interval | ||||
|             emit_count += 1 | ||||
|         return emit_count | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| class EmitterIntervalWithCount(EmitInterval): | ||||
|     """Configure an Emitter to emit particles with given interval, ending after emitting given number of particles""" | ||||
|     def __init__(self, emit_interval: float, particle_count: int): | ||||
|         super().__init__(emit_interval) | ||||
|         self._count_remaining = particle_count | ||||
|  | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         proposed_count = super().how_many(delta_time, current_particle_count) | ||||
|         actual_count = min(proposed_count, self._count_remaining) | ||||
|         self._count_remaining -= actual_count | ||||
|         return actual_count | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         return self._count_remaining <= 0 | ||||
|  | ||||
|  | ||||
| class EmitterIntervalWithTime(EmitInterval): | ||||
|     """Configure an Emitter to emit particles with given interval, ending after given number of seconds""" | ||||
|     def __init__(self, emit_interval: float, lifetime: float): | ||||
|         super().__init__(emit_interval) | ||||
|         self._lifetime = lifetime | ||||
|  | ||||
|     def how_many(self, delta_time: float, current_particle_count: int) -> int: | ||||
|         if self._lifetime <= 0.0: | ||||
|             return 0 | ||||
|         self._lifetime -= delta_time | ||||
|         return super().how_many(delta_time, current_particle_count) | ||||
|  | ||||
|     def is_complete(self) -> bool: | ||||
|         return self._lifetime <= 0 | ||||
|  | ||||
|  | ||||
| # Emitter | ||||
| class Emitter: | ||||
|     """Emits and manages Particles over their lifetime.  The foundational class in a particle system.""" | ||||
|     def __init__( | ||||
|         self, | ||||
|         center_xy: Point, | ||||
|         emit_controller: EmitController, | ||||
|         particle_factory: Callable[["Emitter"], Particle], | ||||
|         change_xy: Vector = (0.0, 0.0), | ||||
|         emit_done_cb: Callable[["Emitter"], None] = None, | ||||
|         reap_cb: Callable[[], None] = None | ||||
|     ): | ||||
|         # Note Self-reference with type annotations: | ||||
|         #     https://www.python.org/dev/peps/pep-0484/#the-problem-of-forward-declarations | ||||
|         self.change_x = change_xy[0] | ||||
|         self.change_y = change_xy[1] | ||||
|  | ||||
|         self.center_x = center_xy[0] | ||||
|         self.center_y = center_xy[1] | ||||
|         self.angle = 0.0 | ||||
|         self.change_angle = 0.0 | ||||
|         self.rate_factory = emit_controller | ||||
|         self.particle_factory = particle_factory | ||||
|         self._emit_done_cb = emit_done_cb | ||||
|         self._reap_cb = reap_cb | ||||
|         self._particles = arcade.SpriteList(use_spatial_hash=False) | ||||
|  | ||||
|     def _emit(self): | ||||
|         """Emit one particle, its initial position and velocity are relative to the position and angle of the emitter""" | ||||
|         p = self.particle_factory(self) | ||||
|         p.center_x += self.center_x | ||||
|         p.center_y += self.center_y | ||||
|  | ||||
|         # given the velocity, rotate it by emitter's current angle | ||||
|         vel = _Vec2(p.change_x, p.change_y).rotated(self.angle) | ||||
|  | ||||
|         p.change_x = vel.x | ||||
|         p.change_y = vel.y | ||||
|         self._particles.append(p) | ||||
|  | ||||
|     def get_count(self): | ||||
|         return len(self._particles) | ||||
|  | ||||
|     def get_pos(self) -> Point: | ||||
|         """Get position of emitter""" | ||||
|         # TODO: should this be a property so a method call isn't needed? | ||||
|         return self.center_x, self.center_y | ||||
|  | ||||
|     def update(self): | ||||
|         # update emitter | ||||
|         self.center_x += self.change_x | ||||
|         self.center_y += self.change_y | ||||
|         self.angle += self.change_angle | ||||
|  | ||||
|         # update particles | ||||
|         emit_count = self.rate_factory.how_many(1 / 60, len(self._particles)) | ||||
|         for _ in range(emit_count): | ||||
|             self._emit() | ||||
|         self._particles.update() | ||||
|         particles_to_reap = [p for p in self._particles if cast(Particle, p).can_reap()] | ||||
|         for dead_particle in particles_to_reap: | ||||
|             dead_particle.kill() | ||||
|  | ||||
|     def draw(self): | ||||
|         self._particles.draw() | ||||
|  | ||||
|     def can_reap(self): | ||||
|         """Determine if Emitter can be deleted""" | ||||
|         is_emit_complete = self.rate_factory.is_complete() | ||||
|         can_reap = is_emit_complete and len(self._particles) <= 0 | ||||
|         if is_emit_complete and self._emit_done_cb: | ||||
|             self._emit_done_cb(self) | ||||
|             self._emit_done_cb = None | ||||
|         if can_reap and self._reap_cb: | ||||
|             self._reap_cb() | ||||
|             self._reap_cb = None | ||||
|         return can_reap | ||||
							
								
								
									
										62
									
								
								arcade/emitter_simple.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,62 @@ | ||||
| """ | ||||
| Convenience functions that provide a much simpler interface to Emitters and Particles. | ||||
|  | ||||
| These trade away some flexibility in favor of simplicity to allow beginners to start using particle systems. | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
| import random | ||||
| from typing import List | ||||
| from arcade.arcade_types import Point | ||||
| from arcade.particle import FilenameOrTexture | ||||
|  | ||||
|  | ||||
| def make_burst_emitter( | ||||
|         center_xy: Point, | ||||
|         filenames_and_textures: List[FilenameOrTexture], | ||||
|         particle_count: int, | ||||
|         particle_speed: float, | ||||
|         particle_lifetime_min: float, | ||||
|         particle_lifetime_max: float, | ||||
|         particle_scale: float = 1.0, | ||||
|         fade_particles: bool = True): | ||||
|     """Returns an emitter that emits all of its particles at once""" | ||||
|     particle_factory = arcade.LifetimeParticle | ||||
|     if fade_particles: | ||||
|         particle_factory = arcade.FadeParticle | ||||
|     return arcade.Emitter( | ||||
|         center_xy=center_xy, | ||||
|         emit_controller=arcade.EmitBurst(particle_count), | ||||
|         particle_factory=lambda emitter: particle_factory( | ||||
|             filename_or_texture=random.choice(filenames_and_textures), | ||||
|             change_xy=arcade.rand_in_circle((0.0, 0.0), particle_speed), | ||||
|             lifetime=random.uniform(particle_lifetime_min, particle_lifetime_max), | ||||
|             scale=particle_scale | ||||
|         ) | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def make_interval_emitter( | ||||
|         center_xy: Point, | ||||
|         filenames_and_textures: List[FilenameOrTexture], | ||||
|         emit_interval: float, | ||||
|         emit_duration: float, | ||||
|         particle_speed: float, | ||||
|         particle_lifetime_min: float, | ||||
|         particle_lifetime_max: float, | ||||
|         particle_scale: float = 1.0, | ||||
|         fade_particles: bool = True): | ||||
|     """Returns an emitter that emits its particles at a constant rate for a given amount of time""" | ||||
|     particle_factory = arcade.LifetimeParticle | ||||
|     if fade_particles: | ||||
|         particle_factory = arcade.FadeParticle | ||||
|     return arcade.Emitter( | ||||
|         center_xy=center_xy, | ||||
|         emit_controller=arcade.EmitterIntervalWithTime(emit_interval, emit_duration), | ||||
|         particle_factory=lambda emitter: particle_factory( | ||||
|             filename_or_texture=random.choice(filenames_and_textures), | ||||
|             change_xy=arcade.rand_on_circle((0.0, 0.0), particle_speed), | ||||
|             lifetime=random.uniform(particle_lifetime_min, particle_lifetime_max), | ||||
|             scale=particle_scale | ||||
|         ) | ||||
|     ) | ||||
							
								
								
									
										0
									
								
								arcade/examples/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										113
									
								
								arcade/examples/array_backed_grid.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,113 @@ | ||||
| """ | ||||
| Array Backed Grid | ||||
|  | ||||
| Show how to use a two-dimensional list/array to back the display of a | ||||
| grid on-screen. | ||||
|  | ||||
| Note: Regular drawing commands are slow. Particularly when drawing a lot of | ||||
| items, like the rectangles in this example. | ||||
|  | ||||
| For faster drawing, create the shapes and then draw them as a batch. | ||||
| See array_backed_grid_buffered.py | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.array_backed_grid | ||||
| """ | ||||
| import arcade | ||||
|  | ||||
| # Set how many rows and columns we will have | ||||
| ROW_COUNT = 15 | ||||
| COLUMN_COUNT = 15 | ||||
|  | ||||
| # This sets the WIDTH and HEIGHT of each grid location | ||||
| WIDTH = 30 | ||||
| HEIGHT = 30 | ||||
|  | ||||
| # This sets the margin between each cell | ||||
| # and on the edges of the screen. | ||||
| MARGIN = 5 | ||||
|  | ||||
| # Do the math to figure out our screen dimensions | ||||
| SCREEN_WIDTH = (WIDTH + MARGIN) * COLUMN_COUNT + MARGIN | ||||
| SCREEN_HEIGHT = (HEIGHT + MARGIN) * ROW_COUNT + MARGIN | ||||
| SCREEN_TITLE = "Array Backed Grid Example" | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ | ||||
|     Main application class. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width, height, title): | ||||
|         """ | ||||
|         Set up the application. | ||||
|         """ | ||||
|  | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         # Create a 2 dimensional array. A two dimensional | ||||
|         # array is simply a list of lists. | ||||
|         self.grid = [] | ||||
|         for row in range(ROW_COUNT): | ||||
|             # Add an empty array that will hold each cell | ||||
|             # in this row | ||||
|             self.grid.append([]) | ||||
|             for column in range(COLUMN_COUNT): | ||||
|                 self.grid[row].append(0)  # Append a cell | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.BLACK) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command has to happen before we start drawing | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # Draw the grid | ||||
|         for row in range(ROW_COUNT): | ||||
|             for column in range(COLUMN_COUNT): | ||||
|                 # Figure out what color to draw the box | ||||
|                 if self.grid[row][column] == 1: | ||||
|                     color = arcade.color.GREEN | ||||
|                 else: | ||||
|                     color = arcade.color.WHITE | ||||
|  | ||||
|                 # Do the math to figure out where the box is | ||||
|                 x = (MARGIN + WIDTH) * column + MARGIN + WIDTH // 2 | ||||
|                 y = (MARGIN + HEIGHT) * row + MARGIN + HEIGHT // 2 | ||||
|  | ||||
|                 # Draw the box | ||||
|                 arcade.draw_rectangle_filled(x, y, WIDTH, HEIGHT, color) | ||||
|  | ||||
|     def on_mouse_press(self, x, y, button, modifiers): | ||||
|         """ | ||||
|         Called when the user presses a mouse button. | ||||
|         """ | ||||
|  | ||||
|         # Change the x/y screen coordinates to grid coordinates | ||||
|         column = x // (WIDTH + MARGIN) | ||||
|         row = y // (HEIGHT + MARGIN) | ||||
|  | ||||
|         print(f"Click coordinates: ({x}, {y}). Grid coordinates: ({row}, {column})") | ||||
|  | ||||
|         # Make sure we are on-grid. It is possible to click in the upper right | ||||
|         # corner in the margin and go to a grid location that doesn't exist | ||||
|         if row < ROW_COUNT and column < COLUMN_COUNT: | ||||
|  | ||||
|             # Flip the location between 1 and 0. | ||||
|             if self.grid[row][column] == 0: | ||||
|                 self.grid[row][column] = 1 | ||||
|             else: | ||||
|                 self.grid[row][column] = 0 | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|  | ||||
|     MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										111
									
								
								arcade/examples/array_backed_grid_buffered.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,111 @@ | ||||
| """ | ||||
| Array Backed Grid | ||||
|  | ||||
| Show how to use a two-dimensional list/array to back the display of a | ||||
| grid on-screen. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.array_backed_grid_buffered | ||||
| """ | ||||
| import arcade | ||||
|  | ||||
| # Set how many rows and columns we will have | ||||
| ROW_COUNT = 15 | ||||
| COLUMN_COUNT = 15 | ||||
|  | ||||
| # This sets the WIDTH and HEIGHT of each grid location | ||||
| WIDTH = 30 | ||||
| HEIGHT = 30 | ||||
|  | ||||
| # This sets the margin between each cell | ||||
| # and on the edges of the screen. | ||||
| MARGIN = 5 | ||||
|  | ||||
| # Do the math to figure out our screen dimensions | ||||
| SCREEN_WIDTH = (WIDTH + MARGIN) * COLUMN_COUNT + MARGIN | ||||
| SCREEN_HEIGHT = (HEIGHT + MARGIN) * ROW_COUNT + MARGIN | ||||
| SCREEN_TITLE = "Array Backed Grid Buffered Example" | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ | ||||
|     Main application class. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width, height, title): | ||||
|         """ | ||||
|         Set up the application. | ||||
|         """ | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         self.shape_list = None | ||||
|  | ||||
|         # Create a 2 dimensional array. A two dimensional | ||||
|         # array is simply a list of lists. | ||||
|         self.grid = [] | ||||
|         for row in range(ROW_COUNT): | ||||
|             # Add an empty array that will hold each cell | ||||
|             # in this row | ||||
|             self.grid.append([]) | ||||
|             for column in range(COLUMN_COUNT): | ||||
|                 self.grid[row].append(0)  # Append a cell | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.BLACK) | ||||
|         self.recreate_grid() | ||||
|  | ||||
|     def recreate_grid(self): | ||||
|         self.shape_list = arcade.ShapeElementList() | ||||
|         for row in range(ROW_COUNT): | ||||
|             for column in range(COLUMN_COUNT): | ||||
|                 if self.grid[row][column] == 0: | ||||
|                     color = arcade.color.WHITE | ||||
|                 else: | ||||
|                     color = arcade.color.GREEN | ||||
|  | ||||
|                 x = (MARGIN + WIDTH) * column + MARGIN + WIDTH // 2 | ||||
|                 y = (MARGIN + HEIGHT) * row + MARGIN + HEIGHT // 2 | ||||
|  | ||||
|                 current_rect = arcade.create_rectangle_filled(x, y, WIDTH, HEIGHT, color) | ||||
|                 self.shape_list.append(current_rect) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command has to happen before we start drawing | ||||
|         arcade.start_render() | ||||
|  | ||||
|         self.shape_list.draw() | ||||
|  | ||||
|     def on_mouse_press(self, x, y, button, modifiers): | ||||
|         """ | ||||
|         Called when the user presses a mouse button. | ||||
|         """ | ||||
|  | ||||
|         # Change the x/y screen coordinates to grid coordinates | ||||
|         column = x // (WIDTH + MARGIN) | ||||
|         row = y // (HEIGHT + MARGIN) | ||||
|  | ||||
|         print(f"Click coordinates: ({x}, {y}). Grid coordinates: ({row}, {column})") | ||||
|  | ||||
|         # Make sure we are on-grid. It is possible to click in the upper right | ||||
|         # corner in the margin and go to a grid location that doesn't exist | ||||
|         if row < ROW_COUNT and column < COLUMN_COUNT: | ||||
|  | ||||
|             # Flip the location between 1 and 0. | ||||
|             if self.grid[row][column] == 0: | ||||
|                 self.grid[row][column] = 1 | ||||
|             else: | ||||
|                 self.grid[row][column] = 0 | ||||
|  | ||||
|         self.recreate_grid() | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										392
									
								
								arcade/examples/asteroid_smasher.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,392 @@ | ||||
| """ | ||||
| Asteroid Smasher | ||||
|  | ||||
| Shoot space rocks in this demo program created with | ||||
| Python and the Arcade library. | ||||
|  | ||||
| Artwork from http://kenney.nl | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.asteroid_smasher | ||||
| """ | ||||
| import random | ||||
| import math | ||||
| import arcade | ||||
| import os | ||||
|  | ||||
| STARTING_ASTEROID_COUNT = 3 | ||||
| SCALE = 0.5 | ||||
| OFFSCREEN_SPACE = 300 | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Asteroid Smasher" | ||||
| LEFT_LIMIT = -OFFSCREEN_SPACE | ||||
| RIGHT_LIMIT = SCREEN_WIDTH + OFFSCREEN_SPACE | ||||
| BOTTOM_LIMIT = -OFFSCREEN_SPACE | ||||
| TOP_LIMIT = SCREEN_HEIGHT + OFFSCREEN_SPACE | ||||
|  | ||||
|  | ||||
| class TurningSprite(arcade.Sprite): | ||||
|     """ Sprite that sets its angle to the direction it is traveling in. """ | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         self.angle = math.degrees(math.atan2(self.change_y, self.change_x)) | ||||
|  | ||||
|  | ||||
| class ShipSprite(arcade.Sprite): | ||||
|     """ | ||||
|     Sprite that represents our space ship. | ||||
|  | ||||
|     Derives from arcade.Sprite. | ||||
|     """ | ||||
|     def __init__(self, filename, scale): | ||||
|         """ Set up the space ship. """ | ||||
|  | ||||
|         # Call the parent Sprite constructor | ||||
|         super().__init__(filename, scale) | ||||
|  | ||||
|         # Info on where we are going. | ||||
|         # Angle comes in automatically from the parent class. | ||||
|         self.thrust = 0 | ||||
|         self.speed = 0 | ||||
|         self.max_speed = 4 | ||||
|         self.drag = 0.05 | ||||
|         self.respawning = 0 | ||||
|  | ||||
|         # Mark that we are respawning. | ||||
|         self.respawn() | ||||
|  | ||||
|     def respawn(self): | ||||
|         """ | ||||
|         Called when we die and need to make a new ship. | ||||
|         'respawning' is an invulnerability timer. | ||||
|         """ | ||||
|         # If we are in the middle of respawning, this is non-zero. | ||||
|         self.respawning = 1 | ||||
|         self.center_x = SCREEN_WIDTH / 2 | ||||
|         self.center_y = SCREEN_HEIGHT / 2 | ||||
|         self.angle = 0 | ||||
|  | ||||
|     def update(self): | ||||
|         """ | ||||
|         Update our position and other particulars. | ||||
|         """ | ||||
|         if self.respawning: | ||||
|             self.respawning += 1 | ||||
|             self.alpha = self.respawning | ||||
|             if self.respawning > 250: | ||||
|                 self.respawning = 0 | ||||
|                 self.alpha = 255 | ||||
|         if self.speed > 0: | ||||
|             self.speed -= self.drag | ||||
|             if self.speed < 0: | ||||
|                 self.speed = 0 | ||||
|  | ||||
|         if self.speed < 0: | ||||
|             self.speed += self.drag | ||||
|             if self.speed > 0: | ||||
|                 self.speed = 0 | ||||
|  | ||||
|         self.speed += self.thrust | ||||
|         if self.speed > self.max_speed: | ||||
|             self.speed = self.max_speed | ||||
|         if self.speed < -self.max_speed: | ||||
|             self.speed = -self.max_speed | ||||
|  | ||||
|         self.change_x = -math.sin(math.radians(self.angle)) * self.speed | ||||
|         self.change_y = math.cos(math.radians(self.angle)) * self.speed | ||||
|  | ||||
|         self.center_x += self.change_x | ||||
|         self.center_y += self.change_y | ||||
|  | ||||
|         """ Call the parent class. """ | ||||
|         super().update() | ||||
|  | ||||
|  | ||||
| class AsteroidSprite(arcade.Sprite): | ||||
|     """ Sprite that represents an asteroid. """ | ||||
|  | ||||
|     def __init__(self, image_file_name, scale): | ||||
|         super().__init__(image_file_name, scale=scale) | ||||
|         self.size = 0 | ||||
|  | ||||
|     def update(self): | ||||
|         """ Move the asteroid around. """ | ||||
|         super().update() | ||||
|         if self.center_x < LEFT_LIMIT: | ||||
|             self.center_x = RIGHT_LIMIT | ||||
|         if self.center_x > RIGHT_LIMIT: | ||||
|             self.center_x = LEFT_LIMIT | ||||
|         if self.center_y > TOP_LIMIT: | ||||
|             self.center_y = BOTTOM_LIMIT | ||||
|         if self.center_y < BOTTOM_LIMIT: | ||||
|             self.center_y = TOP_LIMIT | ||||
|  | ||||
|  | ||||
| class BulletSprite(TurningSprite): | ||||
|     """ | ||||
|     Class that represents a bullet. | ||||
|  | ||||
|     Derives from arcade.TurningSprite which is just a Sprite | ||||
|     that aligns to its direction. | ||||
|     """ | ||||
|  | ||||
|     def update(self): | ||||
|         super().update() | ||||
|         if self.center_x < -100 or self.center_x > 1500 or \ | ||||
|                 self.center_y > 1100 or self.center_y < -100: | ||||
|             self.kill() | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ Main application class. """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|  | ||||
|         # Set the working directory (where we expect to find files) to the same | ||||
|         # directory this .py file is in. You can leave this out of your own | ||||
|         # code, but it is needed to easily run the examples using "python -m" | ||||
|         # as mentioned at the top of this program. | ||||
|         file_path = os.path.dirname(os.path.abspath(__file__)) | ||||
|         os.chdir(file_path) | ||||
|  | ||||
|         self.frame_count = 0 | ||||
|  | ||||
|         self.game_over = False | ||||
|  | ||||
|         # Sprite lists | ||||
|         self.all_sprites_list = None | ||||
|         self.asteroid_list = None | ||||
|         self.bullet_list = None | ||||
|         self.ship_life_list = None | ||||
|  | ||||
|         # Set up the player | ||||
|         self.score = 0 | ||||
|         self.player_sprite = None | ||||
|         self.lives = 3 | ||||
|  | ||||
|         # Sounds | ||||
|         self.laser_sound = arcade.load_sound("sounds/laser1.wav") | ||||
|  | ||||
|     def start_new_game(self): | ||||
|         """ Set up the game and initialize the variables. """ | ||||
|  | ||||
|         self.frame_count = 0 | ||||
|         self.game_over = False | ||||
|  | ||||
|         # Sprite lists | ||||
|         self.all_sprites_list = arcade.SpriteList() | ||||
|         self.asteroid_list = arcade.SpriteList() | ||||
|         self.bullet_list = arcade.SpriteList() | ||||
|         self.ship_life_list = arcade.SpriteList() | ||||
|  | ||||
|         # Set up the player | ||||
|         self.score = 0 | ||||
|         self.player_sprite = ShipSprite("images/playerShip1_orange.png", SCALE) | ||||
|         self.all_sprites_list.append(self.player_sprite) | ||||
|         self.lives = 3 | ||||
|  | ||||
|         # Set up the little icons that represent the player lives. | ||||
|         cur_pos = 10 | ||||
|         for i in range(self.lives): | ||||
|             life = arcade.Sprite("images/playerLife1_orange.png", SCALE) | ||||
|             life.center_x = cur_pos + life.width | ||||
|             life.center_y = life.height | ||||
|             cur_pos += life.width | ||||
|             self.all_sprites_list.append(life) | ||||
|             self.ship_life_list.append(life) | ||||
|  | ||||
|         # Make the asteroids | ||||
|         image_list = ("images/meteorGrey_big1.png", | ||||
|                       "images/meteorGrey_big2.png", | ||||
|                       "images/meteorGrey_big3.png", | ||||
|                       "images/meteorGrey_big4.png") | ||||
|         for i in range(STARTING_ASTEROID_COUNT): | ||||
|             image_no = random.randrange(4) | ||||
|             enemy_sprite = AsteroidSprite(image_list[image_no], SCALE) | ||||
|             enemy_sprite.guid = "Asteroid" | ||||
|  | ||||
|             enemy_sprite.center_y = random.randrange(BOTTOM_LIMIT, TOP_LIMIT) | ||||
|             enemy_sprite.center_x = random.randrange(LEFT_LIMIT, RIGHT_LIMIT) | ||||
|  | ||||
|             enemy_sprite.change_x = random.random() * 2 - 1 | ||||
|             enemy_sprite.change_y = random.random() * 2 - 1 | ||||
|  | ||||
|             enemy_sprite.change_angle = (random.random() - 0.5) * 2 | ||||
|             enemy_sprite.size = 4 | ||||
|             self.all_sprites_list.append(enemy_sprite) | ||||
|             self.asteroid_list.append(enemy_sprite) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command has to happen before we start drawing | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # Draw all the sprites. | ||||
|         self.all_sprites_list.draw() | ||||
|  | ||||
|         # Put the text on the screen. | ||||
|         output = f"Score: {self.score}" | ||||
|         arcade.draw_text(output, 10, 70, arcade.color.WHITE, 13) | ||||
|  | ||||
|         output = f"Asteroid Count: {len(self.asteroid_list)}" | ||||
|         arcade.draw_text(output, 10, 50, arcade.color.WHITE, 13) | ||||
|  | ||||
|     def on_key_press(self, symbol, modifiers): | ||||
|         """ Called whenever a key is pressed. """ | ||||
|         # Shoot if the player hit the space bar and we aren't respawning. | ||||
|         if not self.player_sprite.respawning and symbol == arcade.key.SPACE: | ||||
|             bullet_sprite = BulletSprite("images/laserBlue01.png", SCALE) | ||||
|             bullet_sprite.guid = "Bullet" | ||||
|  | ||||
|             bullet_speed = 13 | ||||
|             bullet_sprite.change_y = \ | ||||
|                 math.cos(math.radians(self.player_sprite.angle)) * bullet_speed | ||||
|             bullet_sprite.change_x = \ | ||||
|                 -math.sin(math.radians(self.player_sprite.angle)) \ | ||||
|                 * bullet_speed | ||||
|  | ||||
|             bullet_sprite.center_x = self.player_sprite.center_x | ||||
|             bullet_sprite.center_y = self.player_sprite.center_y | ||||
|             bullet_sprite.update() | ||||
|  | ||||
|             self.all_sprites_list.append(bullet_sprite) | ||||
|             self.bullet_list.append(bullet_sprite) | ||||
|  | ||||
|             arcade.play_sound(self.laser_sound) | ||||
|  | ||||
|         if symbol == arcade.key.LEFT: | ||||
|             self.player_sprite.change_angle = 3 | ||||
|         elif symbol == arcade.key.RIGHT: | ||||
|             self.player_sprite.change_angle = -3 | ||||
|         elif symbol == arcade.key.UP: | ||||
|             self.player_sprite.thrust = 0.15 | ||||
|         elif symbol == arcade.key.DOWN: | ||||
|             self.player_sprite.thrust = -.2 | ||||
|  | ||||
|     def on_key_release(self, symbol, modifiers): | ||||
|         """ Called whenever a key is released. """ | ||||
|         if symbol == arcade.key.LEFT: | ||||
|             self.player_sprite.change_angle = 0 | ||||
|         elif symbol == arcade.key.RIGHT: | ||||
|             self.player_sprite.change_angle = 0 | ||||
|         elif symbol == arcade.key.UP: | ||||
|             self.player_sprite.thrust = 0 | ||||
|         elif symbol == arcade.key.DOWN: | ||||
|             self.player_sprite.thrust = 0 | ||||
|  | ||||
|     def split_asteroid(self, asteroid: AsteroidSprite): | ||||
|         """ Split an asteroid into chunks. """ | ||||
|         x = asteroid.center_x | ||||
|         y = asteroid.center_y | ||||
|         self.score += 1 | ||||
|  | ||||
|         if asteroid.size == 4: | ||||
|             for i in range(3): | ||||
|                 image_no = random.randrange(2) | ||||
|                 image_list = ["images/meteorGrey_med1.png", | ||||
|                               "images/meteorGrey_med2.png"] | ||||
|  | ||||
|                 enemy_sprite = AsteroidSprite(image_list[image_no], | ||||
|                                               SCALE * 1.5) | ||||
|  | ||||
|                 enemy_sprite.center_y = y | ||||
|                 enemy_sprite.center_x = x | ||||
|  | ||||
|                 enemy_sprite.change_x = random.random() * 2.5 - 1.25 | ||||
|                 enemy_sprite.change_y = random.random() * 2.5 - 1.25 | ||||
|  | ||||
|                 enemy_sprite.change_angle = (random.random() - 0.5) * 2 | ||||
|                 enemy_sprite.size = 3 | ||||
|  | ||||
|                 self.all_sprites_list.append(enemy_sprite) | ||||
|                 self.asteroid_list.append(enemy_sprite) | ||||
|         elif asteroid.size == 3: | ||||
|             for i in range(3): | ||||
|                 image_no = random.randrange(2) | ||||
|                 image_list = ["images/meteorGrey_small1.png", | ||||
|                               "images/meteorGrey_small2.png"] | ||||
|  | ||||
|                 enemy_sprite = AsteroidSprite(image_list[image_no], | ||||
|                                               SCALE * 1.5) | ||||
|  | ||||
|                 enemy_sprite.center_y = y | ||||
|                 enemy_sprite.center_x = x | ||||
|  | ||||
|                 enemy_sprite.change_x = random.random() * 3 - 1.5 | ||||
|                 enemy_sprite.change_y = random.random() * 3 - 1.5 | ||||
|  | ||||
|                 enemy_sprite.change_angle = (random.random() - 0.5) * 2 | ||||
|                 enemy_sprite.size = 2 | ||||
|  | ||||
|                 self.all_sprites_list.append(enemy_sprite) | ||||
|                 self.asteroid_list.append(enemy_sprite) | ||||
|         elif asteroid.size == 2: | ||||
|             for i in range(3): | ||||
|                 image_no = random.randrange(2) | ||||
|                 image_list = ["images/meteorGrey_tiny1.png", | ||||
|                               "images/meteorGrey_tiny2.png"] | ||||
|  | ||||
|                 enemy_sprite = AsteroidSprite(image_list[image_no], | ||||
|                                               SCALE * 1.5) | ||||
|  | ||||
|                 enemy_sprite.center_y = y | ||||
|                 enemy_sprite.center_x = x | ||||
|  | ||||
|                 enemy_sprite.change_x = random.random() * 3.5 - 1.75 | ||||
|                 enemy_sprite.change_y = random.random() * 3.5 - 1.75 | ||||
|  | ||||
|                 enemy_sprite.change_angle = (random.random() - 0.5) * 2 | ||||
|                 enemy_sprite.size = 1 | ||||
|  | ||||
|                 self.all_sprites_list.append(enemy_sprite) | ||||
|                 self.asteroid_list.append(enemy_sprite) | ||||
|  | ||||
|     def update(self, x): | ||||
|         """ Move everything """ | ||||
|  | ||||
|         self.frame_count += 1 | ||||
|  | ||||
|         if not self.game_over: | ||||
|             self.all_sprites_list.update() | ||||
|  | ||||
|             for bullet in self.bullet_list: | ||||
|                 asteroids_plain = arcade.check_for_collision_with_list(bullet, self.asteroid_list) | ||||
|                 asteroids_spatial = arcade.check_for_collision_with_list(bullet, self.asteroid_list) | ||||
|                 if len(asteroids_plain) != len(asteroids_spatial): | ||||
|                     print("ERROR") | ||||
|  | ||||
|                 asteroids = asteroids_spatial | ||||
|  | ||||
|                 for asteroid in asteroids: | ||||
|                     self.split_asteroid(asteroid) | ||||
|                     asteroid.kill() | ||||
|                     bullet.kill() | ||||
|  | ||||
|             if not self.player_sprite.respawning: | ||||
|                 asteroids = arcade.check_for_collision_with_list(self.player_sprite, self.asteroid_list) | ||||
|                 if len(asteroids) > 0: | ||||
|                     if self.lives > 0: | ||||
|                         self.lives -= 1 | ||||
|                         self.player_sprite.respawn() | ||||
|                         self.split_asteroid(asteroids[0]) | ||||
|                         asteroids[0].kill() | ||||
|                         self.ship_life_list.pop().kill() | ||||
|                         print("Crash") | ||||
|                     else: | ||||
|                         self.game_over = True | ||||
|                         print("Game over") | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     window = MyGame() | ||||
|     window.start_new_game() | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										97
									
								
								arcade/examples/bouncing_ball.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,97 @@ | ||||
| """ | ||||
| Bounce a ball on the screen, using gravity. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.bouncing_ball | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
|  | ||||
| # --- Set up the constants | ||||
|  | ||||
| # Size of the screen | ||||
| SCREEN_WIDTH = 600 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Bouncing Ball Example" | ||||
|  | ||||
| # Size of the circle. | ||||
| CIRCLE_RADIUS = 20 | ||||
|  | ||||
| # How strong the gravity is. | ||||
| GRAVITY_CONSTANT = 0.3 | ||||
|  | ||||
| # Percent of velocity maintained on a bounce. | ||||
| BOUNCINESS = 0.9 | ||||
|  | ||||
|  | ||||
| def draw(delta_time): | ||||
|     """ | ||||
|     Use this function to draw everything to the screen. | ||||
|     """ | ||||
|  | ||||
|     # Start the render. This must happen before any drawing | ||||
|     # commands. We do NOT need an stop render command. | ||||
|     arcade.start_render() | ||||
|  | ||||
|     # Draw our rectangle | ||||
|     arcade.draw_circle_filled(draw.x, draw.y, CIRCLE_RADIUS, | ||||
|                               arcade.color.BLACK) | ||||
|  | ||||
|     # Modify rectangles position based on the delta | ||||
|     # vector. (Delta means change. You can also think | ||||
|     # of this as our speed and direction.) | ||||
|     draw.x += draw.delta_x | ||||
|     draw.y += draw.delta_y | ||||
|  | ||||
|     draw.delta_y -= GRAVITY_CONSTANT | ||||
|  | ||||
|     # Figure out if we hit the left or right edge and need to reverse. | ||||
|     if draw.x < CIRCLE_RADIUS and draw.delta_x < 0: | ||||
|         draw.delta_x *= -BOUNCINESS | ||||
|     elif draw.x > SCREEN_WIDTH - CIRCLE_RADIUS and draw.delta_x > 0: | ||||
|         draw.delta_x *= -BOUNCINESS | ||||
|  | ||||
|     # See if we hit the bottom | ||||
|     if draw.y < CIRCLE_RADIUS and draw.delta_y < 0: | ||||
|         # If we bounce with a decent velocity, do a normal bounce. | ||||
|         # Otherwise we won't have enough time resolution to accurate represent | ||||
|         # the bounce and it will bounce forever. So we'll divide the bounciness | ||||
|         # by half to let it settle out. | ||||
|         if draw.delta_y * -1 > GRAVITY_CONSTANT * 15: | ||||
|             draw.delta_y *= -BOUNCINESS | ||||
|         else: | ||||
|             draw.delta_y *= -BOUNCINESS / 2 | ||||
|  | ||||
|  | ||||
| # Below are function-specific variables. Before we use them | ||||
| # in our function, we need to give them initial values. Then | ||||
| # the values will persist between function calls. | ||||
| # | ||||
| # In other languages, we'd declare the variables as 'static' inside the | ||||
| # function to get that same functionality. | ||||
| # | ||||
| # Later on, we'll use 'classes' to track position and velocity for multiple | ||||
| # objects. | ||||
| draw.x = CIRCLE_RADIUS | ||||
| draw.y = SCREEN_HEIGHT - CIRCLE_RADIUS | ||||
| draw.delta_x = 2 | ||||
| draw.delta_y = 0 | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     # Open up our window | ||||
|     arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.set_background_color(arcade.color.WHITE) | ||||
|  | ||||
|     # Tell the computer to call the draw command at the specified interval. | ||||
|     arcade.schedule(draw, 1 / 80) | ||||
|  | ||||
|     # Run the program | ||||
|     arcade.run() | ||||
|  | ||||
|     # When done running the program, close the window. | ||||
|     arcade.close_window() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										113
									
								
								arcade/examples/bouncing_balls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,113 @@ | ||||
| """ | ||||
| Bounce balls on the screen. | ||||
| Spawn a new ball for each mouse-click. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.bouncing_balls | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
| import random | ||||
|  | ||||
| # --- Set up the constants | ||||
|  | ||||
| # Size of the screen | ||||
| SCREEN_WIDTH = 600 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Bouncing Balls Example" | ||||
|  | ||||
|  | ||||
| class Ball: | ||||
|     """ | ||||
|     Class to keep track of a ball's location and vector. | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         self.x = 0 | ||||
|         self.y = 0 | ||||
|         self.change_x = 0 | ||||
|         self.change_y = 0 | ||||
|         self.size = 0 | ||||
|         self.color = None | ||||
|  | ||||
|  | ||||
| def make_ball(): | ||||
|     """ | ||||
|     Function to make a new, random ball. | ||||
|     """ | ||||
|     ball = Ball() | ||||
|  | ||||
|     # Size of the ball | ||||
|     ball.size = random.randrange(10, 30) | ||||
|  | ||||
|     # Starting position of the ball. | ||||
|     # Take into account the ball size so we don't spawn on the edge. | ||||
|     ball.x = random.randrange(ball.size, SCREEN_WIDTH - ball.size) | ||||
|     ball.y = random.randrange(ball.size, SCREEN_HEIGHT - ball.size) | ||||
|  | ||||
|     # Speed and direction of rectangle | ||||
|     ball.change_x = random.randrange(-2, 3) | ||||
|     ball.change_y = random.randrange(-2, 3) | ||||
|  | ||||
|     # Color | ||||
|     ball.color = (random.randrange(256), random.randrange(256), random.randrange(256)) | ||||
|  | ||||
|     return ball | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ Main application class. """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|         self.ball_list = [] | ||||
|         ball = make_ball() | ||||
|         self.ball_list.append(ball) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command has to happen before we start drawing | ||||
|         arcade.start_render() | ||||
|  | ||||
|         for ball in self.ball_list: | ||||
|             arcade.draw_circle_filled(ball.x, ball.y, ball.size, ball.color) | ||||
|  | ||||
|         # Put the text on the screen. | ||||
|         output = "Balls: {}".format(len(self.ball_list)) | ||||
|         arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14) | ||||
|  | ||||
|     def update(self, delta_time): | ||||
|         """ Movement and game logic """ | ||||
|         for ball in self.ball_list: | ||||
|             ball.x += ball.change_x | ||||
|             ball.y += ball.change_y | ||||
|  | ||||
|             if ball.x < ball.size: | ||||
|                 ball.change_x *= -1 | ||||
|  | ||||
|             if ball.y < ball.size: | ||||
|                 ball.change_y *= -1 | ||||
|  | ||||
|             if ball.x > SCREEN_WIDTH - ball.size: | ||||
|                 ball.change_x *= -1 | ||||
|  | ||||
|             if ball.y > SCREEN_HEIGHT - ball.size: | ||||
|                 ball.change_y *= -1 | ||||
|  | ||||
|     def on_mouse_press(self, x, y, button, modifiers): | ||||
|         """ | ||||
|         Called whenever the mouse button is clicked. | ||||
|         """ | ||||
|         ball = make_ball() | ||||
|         self.ball_list.append(ball) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     MyGame() | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										95
									
								
								arcade/examples/bouncing_rectangle.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,95 @@ | ||||
| """ | ||||
| This simple animation example shows how to bounce a rectangle | ||||
| on the screen. | ||||
|  | ||||
| It assumes a programmer knows how to create functions already. | ||||
|  | ||||
| It does not assume a programmer knows how to create classes. If you do know | ||||
| how to create classes, see the starting template for a better example: | ||||
|  | ||||
| http://arcade.academy/examples/starting_template.html | ||||
|  | ||||
| Or look through the examples showing how to use Sprites. | ||||
|  | ||||
| A video walk-through of this example is available at: | ||||
| https://vimeo.com/168063840 | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.bouncing_rectangle | ||||
|  | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
|  | ||||
| # --- Set up the constants | ||||
|  | ||||
| # Size of the screen | ||||
| SCREEN_WIDTH = 600 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Bouncing Rectangle Example" | ||||
|  | ||||
| # Size of the rectangle | ||||
| RECT_WIDTH = 50 | ||||
| RECT_HEIGHT = 50 | ||||
|  | ||||
|  | ||||
| def on_draw(delta_time): | ||||
|     """ | ||||
|     Use this function to draw everything to the screen. | ||||
|     """ | ||||
|  | ||||
|     # Start the render. This must happen before any drawing | ||||
|     # commands. We do NOT need a stop render command. | ||||
|     arcade.start_render() | ||||
|  | ||||
|     # Draw a rectangle. | ||||
|     # For a full list of colors see: | ||||
|     # http://arcade.academy/arcade.color.html | ||||
|     arcade.draw_rectangle_filled(on_draw.center_x, on_draw.center_y, | ||||
|                                  RECT_WIDTH, RECT_HEIGHT, | ||||
|                                  arcade.color.ALIZARIN_CRIMSON) | ||||
|  | ||||
|     # Modify rectangles position based on the delta | ||||
|     # vector. (Delta means change. You can also think | ||||
|     # of this as our speed and direction.) | ||||
|     on_draw.center_x += on_draw.delta_x * delta_time | ||||
|     on_draw.center_y += on_draw.delta_y * delta_time | ||||
|  | ||||
|     # Figure out if we hit the edge and need to reverse. | ||||
|     if on_draw.center_x < RECT_WIDTH // 2 \ | ||||
|             or on_draw.center_x > SCREEN_WIDTH - RECT_WIDTH // 2: | ||||
|         on_draw.delta_x *= -1 | ||||
|     if on_draw.center_y < RECT_HEIGHT // 2 \ | ||||
|             or on_draw.center_y > SCREEN_HEIGHT - RECT_HEIGHT // 2: | ||||
|         on_draw.delta_y *= -1 | ||||
|  | ||||
|  | ||||
| # Below are function-specific variables. Before we use them | ||||
| # in our function, we need to give them initial values. Then | ||||
| # the values will persist between function calls. | ||||
| # | ||||
| # In other languages, we'd declare the variables as 'static' inside the | ||||
| # function to get that same functionality. | ||||
| # | ||||
| # Later on, we'll use 'classes' to track position and velocity for multiple | ||||
| # objects. | ||||
| on_draw.center_x = 100      # Initial x position | ||||
| on_draw.center_y = 50       # Initial y position | ||||
| on_draw.delta_x = 115  # Initial change in x | ||||
| on_draw.delta_y = 130  # Initial change in y | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     # Open up our window | ||||
|     arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.set_background_color(arcade.color.WHITE) | ||||
|  | ||||
|     # Tell the computer to call the draw command at the specified interval. | ||||
|     arcade.schedule(on_draw, 1 / 80) | ||||
|  | ||||
|     # Run the program | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										124
									
								
								arcade/examples/decorator_drawing_example.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,124 @@ | ||||
| """ | ||||
| Example "Arcade" library code. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.decorator_drawing_example | ||||
| """ | ||||
|  | ||||
| # Library imports | ||||
| import arcade | ||||
| import random | ||||
|  | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Drawing With Decorators Example" | ||||
|  | ||||
| window = arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|  | ||||
| bird_list = [] | ||||
|  | ||||
|  | ||||
| def setup(): | ||||
|     create_birds() | ||||
|     arcade.schedule(update, 1 / 60) | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| def create_birds(): | ||||
|     for bird_count in range(10): | ||||
|         x = random.randrange(SCREEN_WIDTH) | ||||
|         y = random.randrange(SCREEN_HEIGHT/2, SCREEN_HEIGHT) | ||||
|         bird_list.append([x, y]) | ||||
|  | ||||
|  | ||||
| def update(delta_time): | ||||
|     """ | ||||
|     This is run every 1/60 of a second or so. Do not draw anything | ||||
|     in this function. | ||||
|     """ | ||||
|     change_y = 0.3 | ||||
|  | ||||
|     for bird in bird_list: | ||||
|         bird[0] += change_y | ||||
|         if bird[0] > SCREEN_WIDTH + 20: | ||||
|             bird[0] = -20 | ||||
|  | ||||
|  | ||||
| @window.event | ||||
| def on_draw(): | ||||
|     """ | ||||
|     This is called every time we need to update our screen. About 60 | ||||
|     times per second. | ||||
|  | ||||
|     Just draw things in this function, don't update where they are. | ||||
|     """ | ||||
|     # Call our drawing functions. | ||||
|     draw_background() | ||||
|     draw_birds() | ||||
|     draw_trees() | ||||
|  | ||||
|  | ||||
| def draw_background(): | ||||
|     """ | ||||
|     This function draws the background. Specifically, the sky and ground. | ||||
|     """ | ||||
|     # Draw the sky in the top two-thirds | ||||
|     arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT * 2 / 3, | ||||
|                                  SCREEN_WIDTH - 1, SCREEN_HEIGHT * 2 / 3, | ||||
|                                  arcade.color.SKY_BLUE) | ||||
|  | ||||
|     # Draw the ground in the bottom third | ||||
|     arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 6, | ||||
|                                  SCREEN_WIDTH - 1, SCREEN_HEIGHT / 3, | ||||
|                                  arcade.color.DARK_SPRING_GREEN) | ||||
|  | ||||
|  | ||||
| def draw_birds(): | ||||
|     for bird in bird_list: | ||||
|         # Draw the bird. | ||||
|         draw_bird(bird[0], bird[1]) | ||||
|  | ||||
|  | ||||
| def draw_bird(x, y): | ||||
|     """ | ||||
|     Draw a bird using a couple arcs. | ||||
|     """ | ||||
|     arcade.draw_arc_outline(x, y, 20, 20, arcade.color.BLACK, 0, 90) | ||||
|     arcade.draw_arc_outline(x + 40, y, 20, 20, arcade.color.BLACK, 90, 180) | ||||
|  | ||||
|  | ||||
| def draw_trees(): | ||||
|  | ||||
|     # Draw the top row of trees | ||||
|     for x in range(45, SCREEN_WIDTH, 90): | ||||
|         draw_pine_tree(x, SCREEN_HEIGHT / 3) | ||||
|  | ||||
|     # Draw the bottom row of trees | ||||
|     for x in range(65, SCREEN_WIDTH, 90): | ||||
|         draw_pine_tree(x, (SCREEN_HEIGHT / 3) - 120) | ||||
|  | ||||
|  | ||||
| def draw_pine_tree(center_x, center_y): | ||||
|     """ | ||||
|     This function draws a pine tree at the specified location. | ||||
|  | ||||
|     Args: | ||||
|       :center_x: x position of the tree center. | ||||
|       :center_y: y position of the tree trunk center. | ||||
|     """ | ||||
|     # Draw the trunk center_x | ||||
|     arcade.draw_rectangle_filled(center_x, center_y, 20, 40, arcade.color.DARK_BROWN) | ||||
|  | ||||
|     tree_bottom_y = center_y + 20 | ||||
|  | ||||
|     # Draw the triangle on top of the trunk | ||||
|     point_list = ((center_x - 40, tree_bottom_y), | ||||
|                   (center_x, tree_bottom_y + 100), | ||||
|                   (center_x + 40, tree_bottom_y)) | ||||
|  | ||||
|     arcade.draw_polygon_filled(point_list, arcade.color.DARK_GREEN) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     setup() | ||||
|  | ||||
							
								
								
									
										168
									
								
								arcade/examples/drawing_primitives.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,168 @@ | ||||
| """ | ||||
| Example "Arcade" library code. | ||||
|  | ||||
| This example shows the drawing primitives and how they are used. | ||||
| It does not assume the programmer knows how to define functions or classes | ||||
| yet. | ||||
|  | ||||
| API documentation for the draw commands can be found here: | ||||
| http://arcade.academy/quick_index.html#id1 | ||||
|  | ||||
| A video explaining this example can be found here: | ||||
| https://vimeo.com/167158158 | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.drawing_primitives | ||||
| """ | ||||
|  | ||||
| # Import the Arcade library. If this fails, then try following the instructions | ||||
| # for how to install arcade: | ||||
| # http://arcade.academy/installation.html | ||||
| import arcade | ||||
| import os | ||||
|  | ||||
| # Set the working directory (where we expect to find files) to the same | ||||
| # directory this .py file is in. You can leave this out of your own | ||||
| # code, but it is needed to easily run the examples using "python -m" | ||||
| # as mentioned at the top of this program. | ||||
| file_path = os.path.dirname(os.path.abspath(__file__)) | ||||
| os.chdir(file_path) | ||||
|  | ||||
| # Open the window. Set the window title and dimensions (width and height) | ||||
| arcade.open_window(600, 600, "Drawing Primitives Example") | ||||
|  | ||||
| # Set the background color to white | ||||
| # For a list of named colors see | ||||
| # http://arcade.academy/arcade.color.html | ||||
| # Colors can also be specified in (red, green, blue) format and | ||||
| # (red, green, blue, alpha) format. | ||||
| arcade.set_background_color(arcade.color.WHITE) | ||||
|  | ||||
| # Start the render process. This must be done before any drawing commands. | ||||
| arcade.start_render() | ||||
|  | ||||
| # Draw a grid | ||||
| # Draw vertical lines every 120 pixels | ||||
| for x in range(0, 601, 120): | ||||
|     arcade.draw_line(x, 0, x, 600, arcade.color.BLACK, 2) | ||||
|  | ||||
| # Draw horizontal lines every 200 pixels | ||||
| for y in range(0, 601, 200): | ||||
|     arcade.draw_line(0, y, 800, y, arcade.color.BLACK, 2) | ||||
|  | ||||
| # Draw a point | ||||
| arcade.draw_text("draw_point", 3, 405, arcade.color.BLACK, 12) | ||||
| arcade.draw_point(60, 495, arcade.color.RED, 10) | ||||
|  | ||||
| # Draw a set of points | ||||
| arcade.draw_text("draw_points", 123, 405, arcade.color.BLACK, 12) | ||||
| point_list = ((165, 495), | ||||
|               (165, 480), | ||||
|               (165, 465), | ||||
|               (195, 495), | ||||
|               (195, 480), | ||||
|               (195, 465)) | ||||
| arcade.draw_points(point_list, arcade.color.ZAFFRE, 10) | ||||
|  | ||||
| # Draw a line | ||||
| arcade.draw_text("draw_line", 243, 405, arcade.color.BLACK, 12) | ||||
| arcade.draw_line(270, 495, 300, 450, arcade.color.WOOD_BROWN, 3) | ||||
|  | ||||
| # Draw a set of lines | ||||
| arcade.draw_text("draw_lines", 363, 405, arcade.color.BLACK, 12) | ||||
| point_list = ((390, 450), | ||||
|               (450, 450), | ||||
|               (390, 480), | ||||
|               (450, 480), | ||||
|               (390, 510), | ||||
|               (450, 510) | ||||
|               ) | ||||
| arcade.draw_lines(point_list, arcade.color.BLUE, 3) | ||||
|  | ||||
| # Draw a line strip | ||||
| arcade.draw_text("draw_line_strip", 483, 405, arcade.color.BLACK, 12) | ||||
| point_list = ((510, 450), | ||||
|               (570, 450), | ||||
|               (510, 480), | ||||
|               (570, 480), | ||||
|               (510, 510), | ||||
|               (570, 510) | ||||
|               ) | ||||
| arcade.draw_line_strip(point_list, arcade.color.TROPICAL_RAIN_FOREST, 3) | ||||
|  | ||||
| # Draw a polygon | ||||
| arcade.draw_text("draw_polygon_outline", 3, 207, arcade.color.BLACK, 9) | ||||
| point_list = ((30, 240), | ||||
|               (45, 240), | ||||
|               (60, 255), | ||||
|               (60, 285), | ||||
|               (45, 300), | ||||
|               (30, 300)) | ||||
| arcade.draw_polygon_outline(point_list, arcade.color.SPANISH_VIOLET, 3) | ||||
|  | ||||
| # Draw a filled in polygon | ||||
| arcade.draw_text("draw_polygon_filled", 123, 207, arcade.color.BLACK, 9) | ||||
| point_list = ((150, 240), | ||||
|               (165, 240), | ||||
|               (180, 255), | ||||
|               (180, 285), | ||||
|               (165, 300), | ||||
|               (150, 300)) | ||||
| arcade.draw_polygon_filled(point_list, arcade.color.SPANISH_VIOLET) | ||||
|  | ||||
| # Draw an outline of a circle | ||||
| arcade.draw_text("draw_circle_outline", 243, 207, arcade.color.BLACK, 10) | ||||
| arcade.draw_circle_outline(300, 285, 18, arcade.color.WISTERIA, 3) | ||||
|  | ||||
| # Draw a filled in circle | ||||
| arcade.draw_text("draw_circle_filled", 363, 207, arcade.color.BLACK, 10) | ||||
| arcade.draw_circle_filled(420, 285, 18, arcade.color.GREEN) | ||||
|  | ||||
| # Draw an ellipse outline, and another one rotated | ||||
| arcade.draw_text("draw_ellipse_outline", 483, 207, arcade.color.BLACK, 10) | ||||
| arcade.draw_ellipse_outline(540, 273, 15, 36, arcade.color.AMBER, 3) | ||||
| arcade.draw_ellipse_outline(540, 336, 15, 36, | ||||
|                             arcade.color.BLACK_BEAN, 3, 45) | ||||
|  | ||||
| # Draw a filled ellipse, and another one rotated | ||||
| arcade.draw_text("draw_ellipse_filled", 3, 3, arcade.color.BLACK, 10) | ||||
| arcade.draw_ellipse_filled(60, 81, 15, 36, arcade.color.AMBER) | ||||
| arcade.draw_ellipse_filled(60, 144, 15, 36, | ||||
|                            arcade.color.BLACK_BEAN, 45) | ||||
|  | ||||
| # Draw an arc, and another one rotated | ||||
| arcade.draw_text("draw_arc/filled_arc", 123, 3, arcade.color.BLACK, 10) | ||||
| arcade.draw_arc_outline(150, 81, 15, 36, | ||||
|                         arcade.color.BRIGHT_MAROON, 90, 360) | ||||
| arcade.draw_arc_filled(150, 144, 15, 36, | ||||
|                        arcade.color.BOTTLE_GREEN, 90, 360, 45) | ||||
|  | ||||
| # Draw an rectangle outline | ||||
| arcade.draw_text("draw_rect", 243, 3, arcade.color.BLACK, 10) | ||||
| arcade.draw_rectangle_outline(295, 100, 45, 65, | ||||
|                               arcade.color.BRITISH_RACING_GREEN) | ||||
| arcade.draw_rectangle_outline(295, 160, 20, 45, | ||||
|                               arcade.color.BRITISH_RACING_GREEN, 3, 45) | ||||
|  | ||||
| # Draw a filled in rectangle | ||||
| arcade.draw_text("draw_filled_rect", 363, 3, arcade.color.BLACK, 10) | ||||
| arcade.draw_rectangle_filled(420, 100, 45, 65, arcade.color.BLUSH) | ||||
| arcade.draw_rectangle_filled(420, 160, 20, 40, arcade.color.BLUSH, 45) | ||||
|  | ||||
| # Load and draw an image to the screen | ||||
| # Image from kenney.nl asset pack #1 | ||||
| arcade.draw_text("draw_bitmap", 483, 3, arcade.color.BLACK, 12) | ||||
| texture = arcade.load_texture("images/playerShip1_orange.png") | ||||
| scale = .6 | ||||
| arcade.draw_texture_rectangle(540, 120, scale * texture.width, | ||||
|                               scale * texture.height, texture, 0) | ||||
| arcade.draw_texture_rectangle(540, 60, scale * texture.width, | ||||
|                               scale * texture.height, texture, 45) | ||||
|  | ||||
| # Finish the render. | ||||
| # Nothing will be drawn without this. | ||||
| # Must happen after all draw commands | ||||
| arcade.finish_render() | ||||
|  | ||||
| # Keep the window up until someone closes it. | ||||
| arcade.run() | ||||
							
								
								
									
										107
									
								
								arcade/examples/drawing_text.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,107 @@ | ||||
| """ | ||||
| Example showing how to draw text to the screen. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.drawing_text | ||||
| """ | ||||
| import arcade | ||||
|  | ||||
| SCREEN_WIDTH = 500 | ||||
| SCREEN_HEIGHT = 500 | ||||
| SCREEN_TITLE = "Drawing Text Example" | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ | ||||
|     Main application class. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width, height, title): | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.WHITE) | ||||
|         self.text_angle = 0 | ||||
|         self.time_elapsed = 0.0 | ||||
|  | ||||
|     def update(self, delta_time): | ||||
|         self.text_angle += 1 | ||||
|         self.time_elapsed += delta_time | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command should happen before we start drawing. It will clear | ||||
|         # the screen to the background color, and erase what we drew last frame. | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # start_x and start_y make the start point for the text. We draw a dot to make it easy too see | ||||
|         # the text in relation to its start x and y. | ||||
|         start_x = 50 | ||||
|         start_y = 450 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Simple line of text in 12 point", start_x, start_y, arcade.color.BLACK, 12) | ||||
|  | ||||
|         start_x = 50 | ||||
|         start_y = 150 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Garamond Text", start_x, start_y, arcade.color.BLACK, 15, font_name='GARA') | ||||
|  | ||||
|         start_x = 50 | ||||
|         start_y = 400 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Text anchored 'top' and 'left'.", | ||||
|                          start_x, start_y, arcade.color.BLACK, 12, anchor_x="left", anchor_y="top") | ||||
|  | ||||
|         start_y = 350 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("14 point multi\nline\ntext", | ||||
|                          start_x, start_y, arcade.color.BLACK, 14, anchor_y="top") | ||||
|  | ||||
|         start_y = 450 | ||||
|         start_x = 300 | ||||
|         width = 200 | ||||
|         height = 20 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_lrtb_rectangle_outline(start_x, start_x + width, | ||||
|                                            start_y + height, start_y, | ||||
|                                            arcade.color.BLUE, 1) | ||||
|         arcade.draw_text("Centered Text.", | ||||
|                          start_x, start_y, arcade.color.BLACK, 14, width=200, align="center") | ||||
|  | ||||
|         start_y = 250 | ||||
|         start_x = 300 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Text centered on\na point", | ||||
|                          start_x, start_y, arcade.color.BLACK, 14, width=200, align="center", | ||||
|                          anchor_x="center", anchor_y="center") | ||||
|  | ||||
|         start_y = 150 | ||||
|         start_x = 300 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Text rotated on\na point", start_x, start_y, | ||||
|                          arcade.color.BLACK, 14, width=200, align="center", anchor_x="center", | ||||
|                          anchor_y="center", rotation=self.text_angle) | ||||
|  | ||||
|         start_y = 150 | ||||
|         start_x = 20 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text("Sideways text", start_x, start_y, | ||||
|                          arcade.color.BLACK, 14, width=200, align="center", | ||||
|                          anchor_x="center", anchor_y="center", rotation=90.0) | ||||
|  | ||||
|         start_y = 20 | ||||
|         start_x = 50 | ||||
|         arcade.draw_point(start_x, start_y, arcade.color.BLUE, 5) | ||||
|         arcade.draw_text(f"Time elapsed: {self.time_elapsed:7.1f}", | ||||
|                          start_x, start_y, arcade.color.BLACK, 14) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										93
									
								
								arcade/examples/drawing_with_functions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,93 @@ | ||||
| """ | ||||
| Example "Arcade" library code. | ||||
|  | ||||
| This example shows how to use functions to draw a scene. | ||||
| It does not assume that the programmer knows how to use classes yet. | ||||
|  | ||||
| A video walk-through of this code is available at: | ||||
| https://vimeo.com/167296062 | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.drawing_with_functions | ||||
| """ | ||||
|  | ||||
| # Library imports | ||||
| import arcade | ||||
|  | ||||
| # Constants - variables that do not change | ||||
| SCREEN_WIDTH = 600 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Drawing With Functions Example" | ||||
|  | ||||
|  | ||||
| def draw_background(): | ||||
|     """ | ||||
|     This function draws the background. Specifically, the sky and ground. | ||||
|     """ | ||||
|     # Draw the sky in the top two-thirds | ||||
|     arcade.draw_lrtb_rectangle_filled(0, | ||||
|                                       SCREEN_WIDTH, | ||||
|                                       SCREEN_HEIGHT, | ||||
|                                       SCREEN_HEIGHT * (1 / 3), | ||||
|                                       arcade.color.SKY_BLUE) | ||||
|  | ||||
|     # Draw the ground in the bottom third | ||||
|     arcade.draw_lrtb_rectangle_filled(0, | ||||
|                                       SCREEN_WIDTH, | ||||
|                                       SCREEN_HEIGHT / 3, | ||||
|                                       0, | ||||
|                                       arcade.color.DARK_SPRING_GREEN) | ||||
|  | ||||
|  | ||||
| def draw_bird(x, y): | ||||
|     """ | ||||
|     Draw a bird using a couple arcs. | ||||
|     """ | ||||
|     arcade.draw_arc_outline(x, y, 20, 20, arcade.color.BLACK, 0, 90) | ||||
|     arcade.draw_arc_outline(x + 40, y, 20, 20, arcade.color.BLACK, 90, 180) | ||||
|  | ||||
|  | ||||
| def draw_pine_tree(x, y): | ||||
|     """ | ||||
|     This function draws a pine tree at the specified location. | ||||
|     """ | ||||
|     # Draw the triangle on top of the trunk | ||||
|     arcade.draw_triangle_filled(x + 40, y, | ||||
|                                 x, y - 100, | ||||
|                                 x + 80, y - 100, | ||||
|                                 arcade.color.DARK_GREEN) | ||||
|  | ||||
|     # Draw the trunk | ||||
|     arcade.draw_lrtb_rectangle_filled(x + 30, x + 50, y - 100, y - 140, | ||||
|                                       arcade.color.DARK_BROWN) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     """ | ||||
|     This is the main program. | ||||
|     """ | ||||
|  | ||||
|     # Open the window | ||||
|     arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|  | ||||
|     # Start the render process. This must be done before any drawing commands. | ||||
|     arcade.start_render() | ||||
|  | ||||
|     # Call our drawing functions. | ||||
|     draw_background() | ||||
|     draw_pine_tree(50, 250) | ||||
|     draw_pine_tree(350, 320) | ||||
|     draw_bird(70, 500) | ||||
|     draw_bird(470, 550) | ||||
|  | ||||
|     # Finish the render. | ||||
|     # Nothing will be drawn without this. | ||||
|     # Must happen after all draw commands | ||||
|     arcade.finish_render() | ||||
|  | ||||
|     # Keep the window up until someone closes it. | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										109
									
								
								arcade/examples/drawing_with_loops.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,109 @@ | ||||
| """ | ||||
| Example "Arcade" library code. | ||||
|  | ||||
| This example shows how to use functions and loops to draw a scene. | ||||
| It does not assume that the programmer knows how to use classes yet. | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.drawing_with_loops | ||||
| """ | ||||
|  | ||||
| # Library imports | ||||
| import arcade | ||||
| import random | ||||
|  | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Drawing With Loops Example" | ||||
|  | ||||
|  | ||||
| def draw_background(): | ||||
|     """ | ||||
|     This function draws the background. Specifically, the sky and ground. | ||||
|     """ | ||||
|     # Draw the sky in the top two-thirds | ||||
|     arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT * 2 / 3, | ||||
|                                  SCREEN_WIDTH - 1, SCREEN_HEIGHT * 2 / 3, | ||||
|                                  arcade.color.SKY_BLUE) | ||||
|  | ||||
|     # Draw the ground in the bottom third | ||||
|     arcade.draw_rectangle_filled(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 6, | ||||
|                                  SCREEN_WIDTH - 1, SCREEN_HEIGHT / 3, | ||||
|                                  arcade.color.DARK_SPRING_GREEN) | ||||
|  | ||||
|  | ||||
| def draw_bird(x, y): | ||||
|     """ | ||||
|     Draw a bird using a couple arcs. | ||||
|     """ | ||||
|     arcade.draw_arc_outline(x, y, 20, 20, arcade.color.BLACK, 0, 90) | ||||
|     arcade.draw_arc_outline(x + 40, y, 20, 20, arcade.color.BLACK, 90, 180) | ||||
|  | ||||
|  | ||||
| def draw_pine_tree(center_x, center_y): | ||||
|     """ | ||||
|     This function draws a pine tree at the specified location. | ||||
|  | ||||
|     Args: | ||||
|       :center_x: x position of the tree center. | ||||
|       :center_y: y position of the tree trunk center. | ||||
|     """ | ||||
|     # Draw the trunkcenter_x | ||||
|     arcade.draw_rectangle_filled(center_x, center_y, 20, 40, | ||||
|                                  arcade.color.DARK_BROWN) | ||||
|  | ||||
|     tree_bottom_y = center_y + 20 | ||||
|  | ||||
|     # Draw the triangle on top of the trunk | ||||
|     point_list = ((center_x - 40, tree_bottom_y), | ||||
|                   (center_x, tree_bottom_y + 100), | ||||
|                   (center_x + 40, tree_bottom_y)) | ||||
|  | ||||
|     arcade.draw_polygon_filled(point_list, arcade.color.DARK_GREEN) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     """ | ||||
|     This is the main program. | ||||
|     """ | ||||
|  | ||||
|     # Open the window | ||||
|     arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|  | ||||
|     # Start the render process. This must be done before any drawing commands. | ||||
|     arcade.start_render() | ||||
|  | ||||
|     # Call our drawing functions. | ||||
|     draw_background() | ||||
|  | ||||
|     # Loop to draw ten birds in random locations. | ||||
|     for bird_count in range(10): | ||||
|         # Any random x from 0 to the width of the screen | ||||
|         x = random.randrange(0, SCREEN_WIDTH) | ||||
|  | ||||
|         # Any random y from in the top 2/3 of the screen. | ||||
|         # No birds on the ground. | ||||
|         y = random.randrange(SCREEN_HEIGHT / 3, SCREEN_HEIGHT - 20) | ||||
|  | ||||
|         # Draw the bird. | ||||
|         draw_bird(x, y) | ||||
|  | ||||
|     # Draw the top row of trees | ||||
|     for x in range(45, SCREEN_WIDTH, 90): | ||||
|         draw_pine_tree(x, SCREEN_HEIGHT / 3) | ||||
|  | ||||
|     # Draw the bottom row of trees | ||||
|     for x in range(65, SCREEN_WIDTH, 90): | ||||
|         draw_pine_tree(x, (SCREEN_HEIGHT / 3) - 120) | ||||
|  | ||||
|     # Finish the render. | ||||
|     # Nothing will be drawn without this. | ||||
|     # Must happen after all draw commands | ||||
|     arcade.finish_render() | ||||
|  | ||||
|     # Keep the window up until someone closes it. | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										310
									
								
								arcade/examples/dual_stick_shooter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,310 @@ | ||||
| """ | ||||
| Dual-stick Shooter Example | ||||
|  | ||||
| A dual-analog stick joystick is the preferred method of input. If a joystick is | ||||
| not present, the game will fail back to use keyboard controls (WASD to move, arrows to shoot) | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.dual_stick_shooter | ||||
| """ | ||||
| import arcade | ||||
| import random | ||||
| import math | ||||
| import os | ||||
| from typing import cast | ||||
| import pprint | ||||
|  | ||||
| SCREEN_WIDTH = 1024 | ||||
| SCREEN_HEIGHT = 768 | ||||
| SCREEN_TITLE = "Dual-stick Shooter Example" | ||||
| MOVEMENT_SPEED = 4 | ||||
| BULLET_SPEED = 10 | ||||
| BULLET_COOLDOWN_TICKS = 10 | ||||
| ENEMY_SPAWN_INTERVAL = 1 | ||||
| ENEMY_SPEED = 1 | ||||
| JOY_DEADZONE = 0.2 | ||||
|  | ||||
|  | ||||
| def dump_obj(obj): | ||||
|     for key in sorted(vars(obj)): | ||||
|         val = getattr(obj, key) | ||||
|         print("{:30} = {} ({})".format(key, val, type(val).__name__)) | ||||
|  | ||||
|  | ||||
| def dump_joystick(joy): | ||||
|     print("========== {}".format(joy)) | ||||
|     print("x       {}".format(joy.x)) | ||||
|     print("y       {}".format(joy.y)) | ||||
|     print("z       {}".format(joy.z)) | ||||
|     print("rx      {}".format(joy.rx)) | ||||
|     print("ry      {}".format(joy.ry)) | ||||
|     print("rz      {}".format(joy.rz)) | ||||
|     print("hat_x   {}".format(joy.hat_x)) | ||||
|     print("hat_y   {}".format(joy.hat_y)) | ||||
|     print("buttons {}".format(joy.buttons)) | ||||
|     print("========== Extra joy") | ||||
|     dump_obj(joy) | ||||
|     print("========== Extra joy.device") | ||||
|     dump_obj(joy.device) | ||||
|     print("========== pprint joy") | ||||
|     pprint.pprint(joy) | ||||
|     print("========== pprint joy.device") | ||||
|     pprint.pprint(joy.device) | ||||
|  | ||||
|  | ||||
| def dump_joystick_state(ticks, joy): | ||||
|     # print("{:5.2f} {:5.2f} {:>20} {:5}_".format(1.234567, -8.2757272903, "hello", str(True))) | ||||
|     fmt_str = "{:6d} " | ||||
|     num_fmts = ["{:5.2f}"] * 6 | ||||
|     fmt_str += " ".join(num_fmts) | ||||
|     fmt_str += " {:2d} {:2d} {}" | ||||
|     buttons = " ".join(["{:5}".format(str(b)) for b in joy.buttons]) | ||||
|     print(fmt_str.format(ticks, | ||||
|                          joy.x, | ||||
|                          joy.y, | ||||
|                          joy.z, | ||||
|                          joy.rx, | ||||
|                          joy.ry, | ||||
|                          joy.rz, | ||||
|                          joy.hat_x, | ||||
|                          joy.hat_y, | ||||
|                          buttons)) | ||||
|  | ||||
|  | ||||
| def get_joy_position(x, y): | ||||
|     """Given position of joystick axes, return (x, y, angle_in_degrees). | ||||
|     If movement is not outside of deadzone, return (None, None, None)""" | ||||
|     if x > JOY_DEADZONE or x < -JOY_DEADZONE or y > JOY_DEADZONE or y < -JOY_DEADZONE: | ||||
|         y = -y | ||||
|         rad = math.atan2(y, x) | ||||
|         angle = math.degrees(rad) | ||||
|         return x, y, angle | ||||
|     return None, None, None | ||||
|  | ||||
|  | ||||
| class Player(arcade.sprite.Sprite): | ||||
|     def __init__(self, filename): | ||||
|         super().__init__(filename=filename, scale=0.4, center_x=SCREEN_WIDTH/2, center_y=SCREEN_HEIGHT/2) | ||||
|         self.shoot_up_pressed = False | ||||
|         self.shoot_down_pressed = False | ||||
|         self.shoot_left_pressed = False | ||||
|         self.shoot_right_pressed = False | ||||
|  | ||||
|  | ||||
| class Enemy(arcade.sprite.Sprite): | ||||
|     def __init__(self, x, y): | ||||
|         super().__init__(filename='images/bumper.png', scale=0.5, center_x=x, center_y=y) | ||||
|  | ||||
|     def follow_sprite(self, player_sprite): | ||||
|         """ | ||||
|         This function will move the current sprite towards whatever | ||||
|         other sprite is specified as a parameter. | ||||
|  | ||||
|         We use the 'min' function here to get the sprite to line up with | ||||
|         the target sprite, and not jump around if the sprite is not off | ||||
|         an exact multiple of ENEMY_SPEED. | ||||
|         """ | ||||
|  | ||||
|         if self.center_y < player_sprite.center_y: | ||||
|             self.center_y += min(ENEMY_SPEED, player_sprite.center_y - self.center_y) | ||||
|         elif self.center_y > player_sprite.center_y: | ||||
|             self.center_y -= min(ENEMY_SPEED, self.center_y - player_sprite.center_y) | ||||
|  | ||||
|         if self.center_x < player_sprite.center_x: | ||||
|             self.center_x += min(ENEMY_SPEED, player_sprite.center_x - self.center_x) | ||||
|         elif self.center_x > player_sprite.center_x: | ||||
|             self.center_x -= min(ENEMY_SPEED, self.center_x - player_sprite.center_x) | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     def __init__(self, width, height, title): | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         # Set the working directory (where we expect to find files) to the same | ||||
|         # directory this .py file is in. You can leave this out of your own | ||||
|         # code, but it is needed to easily run the examples using "python -m" | ||||
|         # as mentioned at the top of this program. | ||||
|         file_path = os.path.dirname(os.path.abspath(__file__)) | ||||
|         os.chdir(file_path) | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.DARK_MIDNIGHT_BLUE) | ||||
|         self.game_over = False | ||||
|         self.score = 0 | ||||
|         self.tick = 0 | ||||
|         self.bullet_cooldown = 0 | ||||
|         self.player = Player("images/playerShip2_orange.png") | ||||
|         self.bullet_list = arcade.SpriteList() | ||||
|         self.enemy_list = arcade.SpriteList() | ||||
|         self.joy = None | ||||
|         joys = arcade.get_joysticks() | ||||
|         for joy in joys: | ||||
|             dump_joystick(joy) | ||||
|         if joys: | ||||
|             self.joy = joys[0] | ||||
|             self.joy.open() | ||||
|             print("Using joystick controls: {}".format(self.joy.device)) | ||||
|             arcade.window_commands.schedule(self.debug_joy_state, 0.1) | ||||
|         if not self.joy: | ||||
|             print("No joystick present, using keyboard controls") | ||||
|         arcade.window_commands.schedule(self.spawn_enemy, ENEMY_SPAWN_INTERVAL) | ||||
|  | ||||
|     def debug_joy_state(self, delta_time): | ||||
|         dump_joystick_state(self.tick, self.joy) | ||||
|  | ||||
|     def spawn_enemy(self, elapsed): | ||||
|         if self.game_over: | ||||
|             return | ||||
|         x = random.randint(0, SCREEN_WIDTH) | ||||
|         y = random.randint(0, SCREEN_HEIGHT) | ||||
|         self.enemy_list.append(Enemy(x, y)) | ||||
|  | ||||
|     def update(self, delta_time): | ||||
|         self.tick += 1 | ||||
|         if self.game_over: | ||||
|             return | ||||
|  | ||||
|         self.bullet_cooldown += 1 | ||||
|  | ||||
|         for enemy in self.enemy_list: | ||||
|             cast(Enemy, enemy).follow_sprite(self.player) | ||||
|  | ||||
|         if self.joy: | ||||
|             # Joystick input - movement | ||||
|             move_x, move_y, move_angle = get_joy_position(self.joy.x, self.joy.y) | ||||
|             if move_angle: | ||||
|                 self.player.change_x = move_x * MOVEMENT_SPEED | ||||
|                 self.player.change_y = move_y * MOVEMENT_SPEED | ||||
|                 # An angle of "0" means "right", but the player's image is drawn in the "up" direction. | ||||
|                 # So an offset is needed. | ||||
|                 self.player.angle = move_angle - 90 | ||||
|             else: | ||||
|                 self.player.change_x = 0 | ||||
|                 self.player.change_y = 0 | ||||
|             # Joystick input - shooting | ||||
|             shoot_x, shoot_y, shoot_angle = get_joy_position(self.joy.z, self.joy.rz) | ||||
|             if shoot_angle: | ||||
|                 self.spawn_bullet(shoot_angle) | ||||
|         else: | ||||
|             # Keyboard input - shooting | ||||
|             if self.player.shoot_right_pressed and self.player.shoot_up_pressed: | ||||
|                 self.spawn_bullet(0+45) | ||||
|             elif self.player.shoot_up_pressed and self.player.shoot_left_pressed: | ||||
|                 self.spawn_bullet(90+45) | ||||
|             elif self.player.shoot_left_pressed and self.player.shoot_down_pressed: | ||||
|                 self.spawn_bullet(180+45) | ||||
|             elif self.player.shoot_down_pressed and self.player.shoot_right_pressed: | ||||
|                 self.spawn_bullet(270+45) | ||||
|             elif self.player.shoot_right_pressed: | ||||
|                 self.spawn_bullet(0) | ||||
|             elif self.player.shoot_up_pressed: | ||||
|                 self.spawn_bullet(90) | ||||
|             elif self.player.shoot_left_pressed: | ||||
|                 self.spawn_bullet(180) | ||||
|             elif self.player.shoot_down_pressed: | ||||
|                 self.spawn_bullet(270) | ||||
|  | ||||
|         self.enemy_list.update() | ||||
|         self.player.update() | ||||
|         self.bullet_list.update() | ||||
|         ship_death_hit_list = arcade.check_for_collision_with_list(self.player, self.enemy_list) | ||||
|         if len(ship_death_hit_list) > 0: | ||||
|             self.game_over = True | ||||
|         for bullet in self.bullet_list: | ||||
|             bullet_killed = False | ||||
|             enemy_shot_list = arcade.check_for_collision_with_list(bullet, self.enemy_list) | ||||
|             # Loop through each colliding sprite, remove it, and add to the score. | ||||
|             for enemy in enemy_shot_list: | ||||
|                 enemy.kill() | ||||
|                 bullet.kill() | ||||
|                 bullet_killed = True | ||||
|                 self.score += 1 | ||||
|             if bullet_killed: | ||||
|                 continue | ||||
|  | ||||
|     def on_key_press(self, key, modifiers): | ||||
|         if key == arcade.key.W: | ||||
|             self.player.change_y = MOVEMENT_SPEED | ||||
|             self.player.angle = 0 | ||||
|         elif key == arcade.key.A: | ||||
|             self.player.change_x = -MOVEMENT_SPEED | ||||
|             self.player.angle = 90 | ||||
|         elif key == arcade.key.S: | ||||
|             self.player.change_y = -MOVEMENT_SPEED | ||||
|             self.player.angle = 180 | ||||
|         elif key == arcade.key.D: | ||||
|             self.player.change_x = MOVEMENT_SPEED | ||||
|             self.player.angle = 270 | ||||
|         elif key == arcade.key.RIGHT: | ||||
|             self.player.shoot_right_pressed = True | ||||
|         elif key == arcade.key.UP: | ||||
|             self.player.shoot_up_pressed = True | ||||
|         elif key == arcade.key.LEFT: | ||||
|             self.player.shoot_left_pressed = True | ||||
|         elif key == arcade.key.DOWN: | ||||
|             self.player.shoot_down_pressed = True | ||||
|  | ||||
|     def on_key_release(self, key, modifiers): | ||||
|         if key == arcade.key.W: | ||||
|             self.player.change_y = 0 | ||||
|         elif key == arcade.key.A: | ||||
|             self.player.change_x = 0 | ||||
|         elif key == arcade.key.S: | ||||
|             self.player.change_y = 0 | ||||
|         elif key == arcade.key.D: | ||||
|             self.player.change_x = 0 | ||||
|         elif key == arcade.key.RIGHT: | ||||
|             self.player.shoot_right_pressed = False | ||||
|         elif key == arcade.key.UP: | ||||
|             self.player.shoot_up_pressed = False | ||||
|         elif key == arcade.key.LEFT: | ||||
|             self.player.shoot_left_pressed = False | ||||
|         elif key == arcade.key.DOWN: | ||||
|             self.player.shoot_down_pressed = False | ||||
|  | ||||
|     def spawn_bullet(self, angle_in_deg): | ||||
|         # only allow bullet to spawn on an interval | ||||
|         if self.bullet_cooldown < BULLET_COOLDOWN_TICKS: | ||||
|             return | ||||
|         self.bullet_cooldown = 0 | ||||
|  | ||||
|         bullet = arcade.Sprite("images/laserBlue01.png", 0.75) | ||||
|  | ||||
|         # Position the bullet at the player's current location | ||||
|         start_x = self.player.center_x | ||||
|         start_y = self.player.center_y | ||||
|         bullet.center_x = start_x | ||||
|         bullet.center_y = start_y | ||||
|  | ||||
|         # angle the bullet visually | ||||
|         bullet.angle = angle_in_deg | ||||
|         angle_in_rad = math.radians(angle_in_deg) | ||||
|  | ||||
|         # set bullet's movement direction | ||||
|         bullet.change_x = math.cos(angle_in_rad) * BULLET_SPEED | ||||
|         bullet.change_y = math.sin(angle_in_rad) * BULLET_SPEED | ||||
|  | ||||
|         # Add the bullet to the appropriate lists | ||||
|         self.bullet_list.append(bullet) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         # clear screen and start render process | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # draw game items | ||||
|         self.bullet_list.draw() | ||||
|         self.enemy_list.draw() | ||||
|         self.player.draw() | ||||
|  | ||||
|         # Put the score on the screen. | ||||
|         output = f"Score: {self.score}" | ||||
|         arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14) | ||||
|  | ||||
|         # Game over message | ||||
|         if self.game_over: | ||||
|             arcade.draw_text("Game Over", SCREEN_WIDTH/2, SCREEN_HEIGHT/2, arcade.color.WHITE, 100, width=SCREEN_WIDTH, | ||||
|                              align="center", anchor_x="center", anchor_y="center") | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.run() | ||||
							
								
								
									
										777
									
								
								arcade/examples/dungeon.tmx
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,777 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <map version="1.0" tiledversion="1.1.5" orientation="isometric" renderorder="right-down" width="10" height="10" tilewidth="256" tileheight="149" infinite="0" nextobjectid="1"> | ||||
|  <tileset firstgid="1" name="Dungeon" tilewidth="256" tileheight="512" tilecount="252" columns="0"> | ||||
|   <grid orientation="orthogonal" width="1" height="1"/> | ||||
|   <tile id="0"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrel_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="1"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrel_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="2"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrel_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="3"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrel_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="4"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrels_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="5"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrels_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="6"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrels_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="7"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrels_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="8"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrelsStacked_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="9"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrelsStacked_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="10"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrelsStacked_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="11"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/barrelsStacked_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="12"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridge_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="13"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridge_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="14"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridge_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="15"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridge_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="16"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridgeBroken_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="17"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridgeBroken_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="18"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridgeBroken_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="19"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/bridgeBroken_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="20"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chair_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="21"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chair_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="22"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chair_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="23"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chair_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="24"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestClosed_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="25"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestClosed_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="26"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestClosed_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="27"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestClosed_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="28"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestOpen_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="29"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestOpen_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="30"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestOpen_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="31"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/chestOpen_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="32"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirt_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="33"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirt_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="34"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirt_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="35"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirt_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="36"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirtTiles_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="37"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirtTiles_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="38"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirtTiles_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="39"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/dirtTiles_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="40"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planks_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="41"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planks_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="42"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planks_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="43"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planks_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="44"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksBroken_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="45"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksBroken_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="46"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksBroken_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="47"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksBroken_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="48"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksHole_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="49"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksHole_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="50"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksHole_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="51"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/planksHole_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="52"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairs_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="53"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairs_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="54"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairs_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="55"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairs_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="56"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsAged_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="57"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsAged_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="58"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsAged_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="59"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsAged_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="60"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsSpiral_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="61"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsSpiral_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="62"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsSpiral_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="63"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stairsSpiral_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="64"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stone_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="65"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stone_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="66"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stone_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="67"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stone_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="68"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumn_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="69"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumn_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="70"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumn_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="71"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumn_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="72"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumnWood_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="73"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumnWood_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="74"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumnWood_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="75"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneColumnWood_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="76"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneLeft_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="77"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneLeft_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="78"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneLeft_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="79"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneLeft_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="80"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneMissingTiles_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="81"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneMissingTiles_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="82"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneMissingTiles_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="83"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneMissingTiles_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="84"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneRight_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="85"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneRight_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="86"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneRight_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="87"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneRight_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="88"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSide_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="89"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSide_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="90"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSide_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="91"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSide_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="92"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSideUneven_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="93"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSideUneven_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="94"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSideUneven_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="95"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSideUneven_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="96"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneStep_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="97"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneStep_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="98"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneStep_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="99"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneStep_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="100"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSteps_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="101"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSteps_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="102"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSteps_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="103"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneSteps_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="104"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneTile_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="105"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneTile_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="106"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneTile_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="107"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneTile_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="108"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneUneven_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="109"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneUneven_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="110"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneUneven_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="111"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneUneven_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="112"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWall_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="113"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWall_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="114"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWall_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="115"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWall_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="116"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAged_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="117"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAged_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="118"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAged_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="119"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAged_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="120"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedLeft_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="121"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedLeft_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="122"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedLeft_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="123"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedLeft_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="124"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedRight_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="125"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedRight_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="126"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedRight_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="127"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallAgedRight_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="128"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallArchway_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="129"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallArchway_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="130"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallArchway_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="131"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallArchway_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="132"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBroken_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="133"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBroken_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="134"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBroken_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="135"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBroken_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="136"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenLeft_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="137"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenLeft_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="138"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenLeft_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="139"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenLeft_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="140"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenRight_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="141"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenRight_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="142"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenRight_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="143"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallBrokenRight_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="144"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumn_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="145"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumn_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="146"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumn_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="147"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumn_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="148"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumnIn_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="149"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumnIn_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="150"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumnIn_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="151"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallColumnIn_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="152"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallCorner_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="153"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallCorner_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="154"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallCorner_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="155"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallCorner_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="156"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoor_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="157"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoor_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="158"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoor_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="159"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoor_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="160"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorBars_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="161"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorBars_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="162"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorBars_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="163"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorBars_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="164"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorClosed_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="165"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorClosed_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="166"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorClosed_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="167"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorClosed_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="168"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorOpen_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="169"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorOpen_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="170"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorOpen_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="171"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallDoorOpen_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="172"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGate_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="173"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGate_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="174"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGate_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="175"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGate_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="176"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateBars_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="177"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateBars_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="178"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateBars_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="179"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateBars_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="180"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateClosed_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="181"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateClosed_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="182"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateClosed_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="183"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateClosed_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="184"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateOpen_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="185"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateOpen_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="186"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateOpen_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="187"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallGateOpen_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="188"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallHole_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="189"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallHole_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="190"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallHole_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="191"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallHole_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="192"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallTop_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="193"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallTop_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="194"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallTop_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="195"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallTop_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="196"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindow_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="197"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindow_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="198"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindow_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="199"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindow_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="200"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindowBars_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="201"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindowBars_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="202"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindowBars_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="203"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/stoneWallWindowBars_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="204"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableChairsBroken_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="205"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableChairsBroken_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="206"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableChairsBroken_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="207"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableChairsBroken_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="208"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRound_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="209"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRound_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="210"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRound_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="211"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRound_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="212"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRoundChairs_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="213"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRoundChairs_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="214"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRoundChairs_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="215"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableRoundChairs_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="216"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShort_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="217"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShort_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="218"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShort_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="219"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShort_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="220"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShortChairs_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="221"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShortChairs_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="222"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShortChairs_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="223"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/tableShortChairs_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="224"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrate_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="225"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrate_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="226"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrate_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="227"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrate_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="228"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrates_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="229"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrates_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="230"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrates_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="231"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenCrates_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="232"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenPile_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="233"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenPile_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="234"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenPile_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="235"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenPile_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="236"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportBeams_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="237"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportBeams_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="238"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportBeams_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="239"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportBeams_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="240"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupports_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="241"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupports_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="242"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupports_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="243"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupports_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="244"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBeam_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="245"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBeam_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="246"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBeam_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="247"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBeam_W.png"/> | ||||
|   </tile> | ||||
|   <tile id="248"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBlock_E.png"/> | ||||
|   </tile> | ||||
|   <tile id="249"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBlock_N.png"/> | ||||
|   </tile> | ||||
|   <tile id="250"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBlock_S.png"/> | ||||
|   </tile> | ||||
|   <tile id="251"> | ||||
|    <image width="256" height="512" source="isometric_dungeon/woodenSupportsBlock_W.png"/> | ||||
|   </tile> | ||||
|  </tileset> | ||||
|  <layer name="Floor" width="10" height="10"> | ||||
|   <data encoding="base64" compression="zlib"> | ||||
|    eJxtkEsOgCAMRLmN5+CzNuGzceMBVIT7ryzJa0KIi5d2YEpHgzHGCYl6CV3wYH9qEF5qE25mdN6iA7qiI9487fT4duHEVznzE453N+HgfujCO1obvWXG4Y30mtNPnkzOTL7hf7iLyzdqrsZMXPZ1+sY/KvgTWndrpoo/c/4BPasgKg== | ||||
|   </data> | ||||
|  </layer> | ||||
|  <layer name="Walls" width="10" height="10"> | ||||
|   <data encoding="base64" compression="zlib"> | ||||
|    eJybxcDAUATFM5HYRWjiJQwIsJMBOyiFqpuIxC9Hws1QejaaeaUkmIdPHQxspdC8nSS6jxh1c4C4GIpnI7GL0cQBoyMZ0g== | ||||
|   </data> | ||||
|  </layer> | ||||
|  <layer name="Furniture" width="10" height="10"> | ||||
|   <data encoding="base64" compression="zlib"> | ||||
|    eJx7wUB98IBC/d/R+GcpNG8oAQAw7AON | ||||
|   </data> | ||||
|  </layer> | ||||
| </map> | ||||
							
								
								
									
										58
									
								
								arcade/examples/frametime_plotter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,58 @@ | ||||
| """ | ||||
| Helper class to track length of time taken for each frame and draw a graph when application exits. | ||||
| Also able to add events at arbitrary times across the graph. | ||||
| """ | ||||
| import time | ||||
| import matplotlib.pyplot as plt | ||||
| import statistics | ||||
|  | ||||
|  | ||||
| class FrametimePlotter: | ||||
|     EVENT_POINT_Y = -0.05 | ||||
|     EVENT_MSG_Y = -0.045 | ||||
|  | ||||
|     def __init__(self): | ||||
|         self.times = [] | ||||
|         self.events = [] | ||||
|         self.start = time.perf_counter() | ||||
|  | ||||
|     def add_event(self, event_msg): | ||||
|         self.events.append((len(self.times), event_msg)) | ||||
|  | ||||
|     def end_frame(self, time_delta): | ||||
|         self.times.append(time_delta) | ||||
|  | ||||
|     def _show_stats(self): | ||||
|         end = time.perf_counter() | ||||
|         print("Min   : {:.5f}".format(min(self.times))) | ||||
|         print("Max   : {:.5f}".format(max(self.times))) | ||||
|         print("Avg   : {:.5f}".format(statistics.mean(self.times))) | ||||
|         print("Median: {:.5f}".format(statistics.median(self.times))) | ||||
|         try: | ||||
|             print("Mode  : {:.5f}".format(statistics.mode(self.times))) | ||||
|         except statistics.StatisticsError as e: | ||||
|             print("Mode  : {}".format(e)) | ||||
|         print("StdDev: {:.5f}".format(statistics.stdev(self.times))) | ||||
|         frame_count = len(self.times) | ||||
|         elapsed_time = end - self.start | ||||
|         print("Frame count: {}".format(frame_count)) | ||||
|         print("Elapsed time: {:.5f}".format(elapsed_time)) | ||||
|         print("FPS: {:.5f}".format(frame_count / elapsed_time)) | ||||
|  | ||||
|     def show(self): | ||||
|         if len(self.times) <= 1: | ||||
|             return | ||||
|         self._show_stats() | ||||
|         frame_idxs = range(0, len(self.times)) | ||||
|         event_idxs = [e[0] for e in self.events] | ||||
|         event_point_y = [self.EVENT_POINT_Y] * len(self.events) | ||||
|         plt.figure("Frame durations", figsize=(8, 6)) | ||||
|         plt.plot(frame_idxs, self.times, event_idxs, event_point_y, "k|") | ||||
|         plt.xlabel("frames") | ||||
|         plt.ylabel("frame duration") | ||||
|         plt.ylim(self.EVENT_POINT_Y - 0.005, 0.5) | ||||
|         plt.tight_layout() | ||||
|         for frame_idx, msg in self.events: | ||||
|             plt.text(frame_idx, self.EVENT_MSG_Y, msg, horizontalalignment="center", verticalalignment="bottom", | ||||
|                      size="smaller", rotation="vertical") | ||||
|         plt.show() | ||||
							
								
								
									
										108
									
								
								arcade/examples/full_screen_example.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,108 @@ | ||||
| """ | ||||
| Use sprites to scroll around a large screen. | ||||
|  | ||||
| Simple program to show basic sprite usage. | ||||
|  | ||||
| Artwork from http://kenney.nl | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.full_screen_example | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
| import os | ||||
|  | ||||
| SPRITE_SCALING = 0.5 | ||||
|  | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Full Screen Example" | ||||
|  | ||||
| # How many pixels to keep as a minimum margin between the character | ||||
| # and the edge of the screen. | ||||
| VIEWPORT_MARGIN = 40 | ||||
|  | ||||
| MOVEMENT_SPEED = 5 | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ Main application class. """ | ||||
|  | ||||
|     def __init__(self): | ||||
|         """ | ||||
|         Initializer | ||||
|         """ | ||||
|         # Open a window in full screen mode. Remove fullscreen=True if | ||||
|         # you don't want to start this way. | ||||
|         super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, fullscreen=True) | ||||
|  | ||||
|         # Set the working directory (where we expect to find files) to the same | ||||
|         # directory this .py file is in. You can leave this out of your own | ||||
|         # code, but it is needed to easily run the examples using "python -m" | ||||
|         # as mentioned at the top of this program. | ||||
|         file_path = os.path.dirname(os.path.abspath(__file__)) | ||||
|         os.chdir(file_path) | ||||
|  | ||||
|         # This will get the size of the window, and set the viewport to match. | ||||
|         # So if the window is 1000x1000, then so will our viewport. If | ||||
|         # you want something different, then use those coordinates instead. | ||||
|         width, height = self.get_size() | ||||
|         self.set_viewport(0, width, 0, height) | ||||
|         arcade.set_background_color(arcade.color.AMAZON) | ||||
|         self.example_image = arcade.load_texture("images/boxCrate_double.png") | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # Get viewport dimensions | ||||
|         left, screen_width, bottom, screen_height = self.get_viewport() | ||||
|  | ||||
|         text_size = 18 | ||||
|         # Draw text on the screen so the user has an idea of what is happening | ||||
|         arcade.draw_text("Press F to toggle between full screen and windowed mode, unstretched.", | ||||
|                          screen_width // 2, screen_height // 2 - 20, | ||||
|                          arcade.color.WHITE, text_size, anchor_x="center") | ||||
|         arcade.draw_text("Press S to toggle between full screen and windowed mode, stretched.", | ||||
|                          screen_width // 2, screen_height // 2 + 20, | ||||
|                          arcade.color.WHITE, text_size, anchor_x="center") | ||||
|  | ||||
|         # Draw some boxes on the bottom so we can see how they change | ||||
|         for x in range(64, 800, 128): | ||||
|             y = 64 | ||||
|             width = 128 | ||||
|             height = 128 | ||||
|             arcade.draw_texture_rectangle(x, y, width, height, self.example_image) | ||||
|  | ||||
|     def on_key_press(self, key, modifiers): | ||||
|         """Called whenever a key is pressed. """ | ||||
|         if key == arcade.key.F: | ||||
|             # User hits f. Flip between full and not full screen. | ||||
|             self.set_fullscreen(not self.fullscreen) | ||||
|  | ||||
|             # Get the window coordinates. Match viewport to window coordinates | ||||
|             # so there is a one-to-one mapping. | ||||
|             width, height = self.get_size() | ||||
|             self.set_viewport(0, width, 0, height) | ||||
|  | ||||
|         if key == arcade.key.S: | ||||
|             # User hits s. Flip between full and not full screen. | ||||
|             self.set_fullscreen(not self.fullscreen) | ||||
|  | ||||
|             # Instead of a one-to-one mapping, stretch/squash window to match the | ||||
|             # constants. This does NOT respect aspect ratio. You'd need to | ||||
|             # do a bit of math for that. | ||||
|             self.set_viewport(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     """ Main method """ | ||||
|     MyGame() | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										92
									
								
								arcade/examples/gradients.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,92 @@ | ||||
| """ | ||||
| Drawing Gradients | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.gradients | ||||
| """ | ||||
| import arcade | ||||
|  | ||||
| # Do the math to figure out our screen dimensions | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Gradients Example" | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ | ||||
|     Main application class. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width, height, title): | ||||
|         """ | ||||
|         Set up the application. | ||||
|         """ | ||||
|  | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.BLACK) | ||||
|  | ||||
|         self.shapes = arcade.ShapeElementList() | ||||
|  | ||||
|         # This is a large rectangle that fills the whole | ||||
|         # background. The gradient goes between the two colors | ||||
|         # top to bottom. | ||||
|         color1 = (215, 214, 165) | ||||
|         color2 = (219, 166, 123) | ||||
|         points = (0, 0), (SCREEN_WIDTH, 0), (SCREEN_WIDTH, SCREEN_HEIGHT), (0, SCREEN_HEIGHT) | ||||
|         colors = (color1, color1, color2, color2) | ||||
|         rect = arcade.create_rectangle_filled_with_colors(points, colors) | ||||
|         self.shapes.append(rect) | ||||
|  | ||||
|         # Another rectangle, but in this case the color doesn't change. Just the | ||||
|         # transparency. This time it goes from left to right. | ||||
|         color1 = (165, 92, 85, 255) | ||||
|         color2 = (165, 92, 85, 0) | ||||
|         points = (100, 100), (SCREEN_WIDTH - 100, 100), (SCREEN_WIDTH - 100, 300), (100, 300) | ||||
|         colors = (color2, color1, color1, color2) | ||||
|         rect = arcade.create_rectangle_filled_with_colors(points, colors) | ||||
|         self.shapes.append(rect) | ||||
|  | ||||
|         # Two lines | ||||
|         color1 = (7, 67, 88) | ||||
|         color2 = (69, 137, 133) | ||||
|         points = (100, 400), (SCREEN_WIDTH - 100, 400), (SCREEN_WIDTH - 100, 500), (100, 500) | ||||
|         colors = (color2, color1, color2, color1) | ||||
|         shape = arcade.create_lines_with_colors(points, colors, line_width=5) | ||||
|         self.shapes.append(shape) | ||||
|  | ||||
|         # Triangle | ||||
|         color1 = (215, 214, 165) | ||||
|         color2 = (219, 166, 123) | ||||
|         color3 = (165, 92, 85) | ||||
|         points = (SCREEN_WIDTH // 2, 500), (SCREEN_WIDTH // 2 - 100, 400), (SCREEN_WIDTH // 2 + 100, 400) | ||||
|         colors = (color1, color2, color3) | ||||
|         shape = arcade.create_triangles_filled_with_colors(points, colors) | ||||
|         self.shapes.append(shape) | ||||
|  | ||||
|         # Ellipse, gradient between center and outside | ||||
|         color1 = (69, 137, 133, 127) | ||||
|         color2 = (7, 67, 88, 127) | ||||
|         shape = arcade.create_ellipse_filled_with_colors(SCREEN_WIDTH // 2, 350, 50, 50, | ||||
|                                                          inside_color=color1, outside_color=color2) | ||||
|         self.shapes.append(shape) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         # This command has to happen before we start drawing | ||||
|         arcade.start_render() | ||||
|         self.shapes.draw() | ||||
|         # arcade.draw_rectangle_filled(500, 500, 50, 50, (255, 0, 0, 127)) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|  | ||||
|     MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										238
									
								
								arcade/examples/gui_text_button.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,238 @@ | ||||
| """ | ||||
| Buttons with text on them | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.gui_text_button | ||||
| """ | ||||
| import arcade | ||||
| import random | ||||
| import os | ||||
|  | ||||
| SCREEN_WIDTH = 800 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "GUI Text Buton Example" | ||||
|  | ||||
|  | ||||
| class TextButton: | ||||
|     """ Text-based button """ | ||||
|  | ||||
|     def __init__(self, | ||||
|                  center_x, center_y, | ||||
|                  width, height, | ||||
|                  text, | ||||
|                  font_size=18, | ||||
|                  font_face="Arial", | ||||
|                  face_color=arcade.color.LIGHT_GRAY, | ||||
|                  highlight_color=arcade.color.WHITE, | ||||
|                  shadow_color=arcade.color.GRAY, | ||||
|                  button_height=2): | ||||
|         self.center_x = center_x | ||||
|         self.center_y = center_y | ||||
|         self.width = width | ||||
|         self.height = height | ||||
|         self.text = text | ||||
|         self.font_size = font_size | ||||
|         self.font_face = font_face | ||||
|         self.pressed = False | ||||
|         self.face_color = face_color | ||||
|         self.highlight_color = highlight_color | ||||
|         self.shadow_color = shadow_color | ||||
|         self.button_height = button_height | ||||
|  | ||||
|     def draw(self): | ||||
|         """ Draw the button """ | ||||
|         arcade.draw_rectangle_filled(self.center_x, self.center_y, self.width, | ||||
|                                      self.height, self.face_color) | ||||
|  | ||||
|         if not self.pressed: | ||||
|             color = self.shadow_color | ||||
|         else: | ||||
|             color = self.highlight_color | ||||
|  | ||||
|         # Bottom horizontal | ||||
|         arcade.draw_line(self.center_x - self.width / 2, self.center_y - self.height / 2, | ||||
|                          self.center_x + self.width / 2, self.center_y - self.height / 2, | ||||
|                          color, self.button_height) | ||||
|  | ||||
|         # Right vertical | ||||
|         arcade.draw_line(self.center_x + self.width / 2, self.center_y - self.height / 2, | ||||
|                          self.center_x + self.width / 2, self.center_y + self.height / 2, | ||||
|                          color, self.button_height) | ||||
|  | ||||
|         if not self.pressed: | ||||
|             color = self.highlight_color | ||||
|         else: | ||||
|             color = self.shadow_color | ||||
|  | ||||
|         # Top horizontal | ||||
|         arcade.draw_line(self.center_x - self.width / 2, self.center_y + self.height / 2, | ||||
|                          self.center_x + self.width / 2, self.center_y + self.height / 2, | ||||
|                          color, self.button_height) | ||||
|  | ||||
|         # Left vertical | ||||
|         arcade.draw_line(self.center_x - self.width / 2, self.center_y - self.height / 2, | ||||
|                          self.center_x - self.width / 2, self.center_y + self.height / 2, | ||||
|                          color, self.button_height) | ||||
|  | ||||
|         x = self.center_x | ||||
|         y = self.center_y | ||||
|         if not self.pressed: | ||||
|             x -= self.button_height | ||||
|             y += self.button_height | ||||
|  | ||||
|         arcade.draw_text(self.text, x, y, | ||||
|                          arcade.color.BLACK, font_size=self.font_size, | ||||
|                          width=self.width, align="center", | ||||
|                          anchor_x="center", anchor_y="center") | ||||
|  | ||||
|     def on_press(self): | ||||
|         self.pressed = True | ||||
|  | ||||
|     def on_release(self): | ||||
|         self.pressed = False | ||||
|  | ||||
|  | ||||
| def check_mouse_press_for_buttons(x, y, button_list): | ||||
|     """ Given an x, y, see if we need to register any button clicks. """ | ||||
|     for button in button_list: | ||||
|         if x > button.center_x + button.width / 2: | ||||
|             continue | ||||
|         if x < button.center_x - button.width / 2: | ||||
|             continue | ||||
|         if y > button.center_y + button.height / 2: | ||||
|             continue | ||||
|         if y < button.center_y - button.height / 2: | ||||
|             continue | ||||
|         button.on_press() | ||||
|  | ||||
|  | ||||
| def check_mouse_release_for_buttons(x, y, button_list): | ||||
|     """ If a mouse button has been released, see if we need to process | ||||
|         any release events. """ | ||||
|     for button in button_list: | ||||
|         if button.pressed: | ||||
|             button.on_release() | ||||
|  | ||||
|  | ||||
| class StartTextButton(TextButton): | ||||
|     def __init__(self, center_x, center_y, action_function): | ||||
|         super().__init__(center_x, center_y, 100, 40, "Start", 18, "Arial") | ||||
|         self.action_function = action_function | ||||
|  | ||||
|     def on_release(self): | ||||
|         super().on_release() | ||||
|         self.action_function() | ||||
|  | ||||
|  | ||||
| class StopTextButton(TextButton): | ||||
|     def __init__(self, center_x, center_y, action_function): | ||||
|         super().__init__(center_x, center_y, 100, 40, "Stop", 18, "Arial") | ||||
|         self.action_function = action_function | ||||
|  | ||||
|     def on_release(self): | ||||
|         super().on_release() | ||||
|         self.action_function() | ||||
|  | ||||
|  | ||||
| class MyGame(arcade.Window): | ||||
|     """ | ||||
|     Main application class. | ||||
|  | ||||
|     NOTE: Go ahead and delete the methods you don't need. | ||||
|     If you do need a method, delete the 'pass' and replace it | ||||
|     with your own code. Don't leave 'pass' in this program. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, width, height, title): | ||||
|         super().__init__(width, height, title) | ||||
|  | ||||
|         # Set the working directory (where we expect to find files) to the same | ||||
|         # directory this .py file is in. You can leave this out of your own | ||||
|         # code, but it is needed to easily run the examples using "python -m" | ||||
|         # as mentioned at the top of this program. | ||||
|         file_path = os.path.dirname(os.path.abspath(__file__)) | ||||
|         os.chdir(file_path) | ||||
|  | ||||
|         arcade.set_background_color(arcade.color.AMAZON) | ||||
|  | ||||
|         self.pause = False | ||||
|         self.coin_list = None | ||||
|         self.button_list = None | ||||
|  | ||||
|     def setup(self): | ||||
|         # Create your sprites and sprite lists here | ||||
|         self.coin_list = arcade.SpriteList() | ||||
|         for i in range(10): | ||||
|             coin = arcade.Sprite("images/coin_01.png", 0.25) | ||||
|             coin.center_x = random.randrange(SCREEN_WIDTH) | ||||
|             coin.center_y = random.randrange(SCREEN_HEIGHT) | ||||
|             coin.change_y = -1 | ||||
|             self.coin_list.append(coin) | ||||
|  | ||||
|         # Create our on-screen GUI buttons | ||||
|         self.button_list = [] | ||||
|  | ||||
|         play_button = StartTextButton(60, 570, self.resume_program) | ||||
|         self.button_list.append(play_button) | ||||
|  | ||||
|         quit_button = StopTextButton(60, 515, self.pause_program) | ||||
|         self.button_list.append(quit_button) | ||||
|  | ||||
|     def on_draw(self): | ||||
|         """ | ||||
|         Render the screen. | ||||
|         """ | ||||
|  | ||||
|         arcade.start_render() | ||||
|  | ||||
|         # Draw the coins | ||||
|         self.coin_list.draw() | ||||
|  | ||||
|         # Draw the buttons | ||||
|         for button in self.button_list: | ||||
|             button.draw() | ||||
|  | ||||
|     def update(self, delta_time): | ||||
|         """ | ||||
|         All the logic to move, and the game logic goes here. | ||||
|         Normally, you'll call update() on the sprite lists that | ||||
|         need it. | ||||
|         """ | ||||
|  | ||||
|         if self.pause: | ||||
|             return | ||||
|  | ||||
|         self.coin_list.update() | ||||
|  | ||||
|         for coin in self.coin_list: | ||||
|             if coin.top < 0: | ||||
|                 coin.bottom = SCREEN_HEIGHT | ||||
|  | ||||
|     def on_mouse_press(self, x, y, button, key_modifiers): | ||||
|         """ | ||||
|         Called when the user presses a mouse button. | ||||
|         """ | ||||
|         check_mouse_press_for_buttons(x, y, self.button_list) | ||||
|  | ||||
|     def on_mouse_release(self, x, y, button, key_modifiers): | ||||
|         """ | ||||
|         Called when a user releases a mouse button. | ||||
|         """ | ||||
|         check_mouse_release_for_buttons(x, y, self.button_list) | ||||
|  | ||||
|     def pause_program(self): | ||||
|         self.pause = True | ||||
|  | ||||
|     def resume_program(self): | ||||
|         self.pause = False | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     """ Main method """ | ||||
|     game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|     game.setup() | ||||
|     arcade.run() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
							
								
								
									
										48
									
								
								arcade/examples/happy_face.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,48 @@ | ||||
| """ | ||||
| Drawing an example happy face | ||||
|  | ||||
| If Python and Arcade are installed, this example can be run from the command line with: | ||||
| python -m arcade.examples.happy_face | ||||
| """ | ||||
|  | ||||
| import arcade | ||||
|  | ||||
| # Set constants for the screen size | ||||
| SCREEN_WIDTH = 600 | ||||
| SCREEN_HEIGHT = 600 | ||||
| SCREEN_TITLE = "Happy Face Example" | ||||
|  | ||||
| # Open the window. Set the window title and dimensions | ||||
| arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) | ||||
|  | ||||
| # Set the background color | ||||
| arcade.set_background_color(arcade.color.WHITE) | ||||
|  | ||||
| # Clear screen and start render process | ||||
| arcade.start_render() | ||||
|  | ||||
| # --- Drawing Commands Will Go Here --- | ||||
|  | ||||
| # Draw the face | ||||
| x = 300; y = 300; radius = 200 | ||||
| arcade.draw_circle_filled(x, y, radius, arcade.color.YELLOW) | ||||
|  | ||||
| # Draw the right eye | ||||
| x = 370; y = 350; radius = 20 | ||||
| arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK) | ||||
|  | ||||
| # Draw the left eye | ||||
| x = 230; y = 350; radius = 20 | ||||
| arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK) | ||||
|  | ||||
| # Draw the smile | ||||
| x = 300; y = 280; width = 120; height = 100 | ||||
| start_angle = 190; end_angle = 350 | ||||
| arcade.draw_arc_outline(x, y, width, height, arcade.color.BLACK, | ||||
|                         start_angle, end_angle, 10) | ||||
|  | ||||
| # Finish drawing and display the result | ||||
| arcade.finish_render() | ||||
|  | ||||
| # Keep the window open until the user hits the 'close' button | ||||
| arcade.run() | ||||
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/background.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 26 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/background_2.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 46 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/boxCrate_double.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/bumper.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.6 KiB | 
							
								
								
									
										100
									
								
								arcade/examples/images/bumper.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,100 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="95.954338" | ||||
|    height="95.954338" | ||||
|    id="svg2" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.4 r9939" | ||||
|    sodipodi:docname="bumper.svg" | ||||
|    inkscape:export-filename="C:\Users\craven\Desktop\WebServer\arcade\examples\images\bumper.png" | ||||
|    inkscape:export-xdpi="90" | ||||
|    inkscape:export-ydpi="90"> | ||||
|   <defs | ||||
|      id="defs4" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="3.959798" | ||||
|      inkscape:cx="-18.856048" | ||||
|      inkscape:cy="41.144234" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      inkscape:window-width="1422" | ||||
|      inkscape:window-height="895" | ||||
|      inkscape:window-x="26" | ||||
|      inkscape:window-y="26" | ||||
|      inkscape:window-maximized="0" | ||||
|      showguides="true" | ||||
|      inkscape:guide-bbox="true" | ||||
|      fit-margin-top="0" | ||||
|      fit-margin-left="0" | ||||
|      fit-margin-right="0" | ||||
|      fit-margin-bottom="0" /> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-62.129459,-72.014217)"> | ||||
|     <path | ||||
|        sodipodi:type="arc" | ||||
|        style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|        id="path2985" | ||||
|        sodipodi:cx="110.10663" | ||||
|        sodipodi:cy="119.99139" | ||||
|        sodipodi:rx="47.477169" | ||||
|        sodipodi:ry="47.477169" | ||||
|        d="m 157.5838,119.99139 c 0,26.22091 -21.25626,47.47717 -47.47717,47.47717 -26.220918,0 -47.477171,-21.25626 -47.477171,-47.47717 0,-26.22092 21.256253,-47.477173 47.477171,-47.477173 26.22091,0 47.47717,21.256253 47.47717,47.477173 z" /> | ||||
|     <path | ||||
|        sodipodi:type="star" | ||||
|        style="fill:#ffff00;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|        id="path2991" | ||||
|        sodipodi:sides="10" | ||||
|        sodipodi:cx="78.286819" | ||||
|        sodipodi:cy="98.525642" | ||||
|        sodipodi:r1="50.346378" | ||||
|        sodipodi:r2="25.173187" | ||||
|        sodipodi:arg1="0.70372968" | ||||
|        sodipodi:arg2="1.0178889" | ||||
|        inkscape:flatsided="false" | ||||
|        inkscape:rounded="0" | ||||
|        inkscape:randomized="0" | ||||
|        d="m 116.67262,131.10306 -25.165757,-11.155 -1.313808,27.49588 -13.802775,-23.81665 -17.224565,21.47239 2.832396,-27.38114 -26.556123,7.24719 18.385687,-20.48697 -25.744146,-9.746198 26.916272,-5.76747 -15.09878,-23.01687 25.165755,11.155007 1.313808,-27.495879 13.802775,23.816649 17.224564,-21.472396 -2.832395,27.381141 26.556122,-7.247188 -18.38569,20.486968 25.74415,9.746196 -26.91627,5.76747 z" | ||||
|        transform="matrix(0.90275471,0,0,0.91785308,38.801484,29.938127)" /> | ||||
|     <path | ||||
|        sodipodi:type="arc" | ||||
|        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|        id="path2995" | ||||
|        sodipodi:cx="110.35917" | ||||
|        sodipodi:cy="121.75915" | ||||
|        sodipodi:rx="22.475895" | ||||
|        sodipodi:ry="22.475895" | ||||
|        d="m 132.83506,121.75915 c 0,12.41309 -10.0628,22.47589 -22.47589,22.47589 -12.413095,0 -22.475896,-10.0628 -22.475896,-22.47589 0,-12.4131 10.062801,-22.475897 22.475896,-22.475897 12.41309,0 22.47589,10.062797 22.47589,22.475897 z" | ||||
|        transform="translate(-0.75761441,-1.767767)" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sheet.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 124 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character10.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character14.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character15.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character17.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character18.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/character7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/characterw0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/characterw1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/characterw2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/character_sprites/characterw3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/coin_01.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0000.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0001.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0002.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0003.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0004.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0005.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0006.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0007.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0008.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0009.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0010.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0011.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0012.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0013.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0014.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0015.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0016.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0017.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0018.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0019.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 8.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0020.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 8.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0021.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0022.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0023.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0024.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0025.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0026.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 13 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0027.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 13 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0028.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0029.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0030.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0031.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0032.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0033.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0034.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0035.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0036.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0037.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0038.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0039.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 18 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0040.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 18 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0041.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 19 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0042.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 19 KiB | 
							
								
								
									
										
											BIN
										
									
								
								arcade/examples/images/explosion/explosion0043.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 19 KiB |