From 705a594023ee7d28e25510cc19b6ec799f6bf480 Mon Sep 17 00:00:00 2001 From: NaboKabbo <101510622+PythonChicken123@users.noreply.github.com> Date: Fri, 1 Dec 2023 22:03:08 +0000 Subject: [PATCH] Add files via upload --- docs/c_api.rst | 25 + docs/common.txt | 14 + docs/conf.py | 262 ++- docs/filepaths.rst | 17 + docs/index.rst | 218 +- docs/logos.rst | 47 + docs/ref/bufferproxy.rst | 113 + docs/ref/camera.rst | 250 ++ docs/ref/cdrom.rst | 310 +++ docs/ref/code_examples/angle_to.png | Bin 0 -> 25349 bytes docs/ref/code_examples/base_script.py | 27 + docs/ref/code_examples/base_script_example.py | 43 + .../code_examples/cursors_module_example.py | 44 + .../ref/code_examples/draw_module_example.png | Bin 0 -> 6476 bytes docs/ref/code_examples/draw_module_example.py | 92 + docs/ref/code_examples/joystick_calls.png | Bin 0 -> 30004 bytes docs/ref/color.rst | 283 +++ docs/ref/color_list.rst | 2014 +++++++++++++++++ docs/ref/common.txt | 2 + docs/ref/cursors.rst | 251 ++ docs/ref/display.rst | 737 ++++++ docs/ref/draw.rst | 557 +++++ docs/ref/event.rst | 565 +++++ docs/ref/examples.rst | 451 ++++ docs/ref/fastevent.rst | 109 + docs/ref/font.rst | 499 ++++ docs/ref/freetype.rst | 770 +++++++ docs/ref/gfxdraw.rst | 628 +++++ docs/ref/image.rst | 375 +++ docs/ref/joystick.rst | 697 ++++++ docs/ref/key.rst | 455 ++++ docs/ref/locals.rst | 27 + docs/ref/mask.rst | 642 ++++++ docs/ref/math.rst | 1143 ++++++++++ docs/ref/midi.rst | 484 ++++ docs/ref/mixer.rst | 605 +++++ docs/ref/mouse.rst | 219 ++ docs/ref/music.rst | 274 +++ docs/ref/overlay.rst | 79 + docs/ref/pixelarray.rst | 295 +++ docs/ref/pixelcopy.rst | 104 + docs/ref/pygame.rst | 505 +++++ docs/ref/rect.rst | 604 +++++ docs/ref/scrap.rst | 240 ++ docs/ref/sdl2_controller.rst | 290 +++ docs/ref/sdl2_video.rst | 334 +++ docs/ref/sndarray.rst | 95 + docs/ref/sprite.rst | 895 ++++++++ docs/ref/surface.rst | 949 ++++++++ docs/ref/surfarray.rst | 337 +++ docs/ref/tests.rst | 113 + docs/ref/time.rst | 165 ++ docs/ref/touch.rst | 66 + docs/ref/transform.rst | 325 +++ docs/tut/CameraIntro.rst | 299 +++ docs/tut/ChimpLineByLine.rst | 541 +++++ docs/tut/DisplayModes.rst | 197 ++ docs/tut/ImportInit.rst | 76 + docs/tut/MakeGames.rst | 136 ++ docs/tut/MoveIt.rst | 603 +++++ docs/tut/PygameIntro.rst | 301 +++ docs/tut/SpriteIntro.rst | 415 ++++ docs/tut/SurfarrayIntro-rest | 114 + docs/tut/SurfarrayIntro.rst | 580 +++++ docs/tut/camera_average.jpg | Bin 0 -> 20881 bytes docs/tut/camera_background.jpg | Bin 0 -> 7493 bytes docs/tut/camera_green.jpg | Bin 0 -> 10219 bytes docs/tut/camera_hsv.jpg | Bin 0 -> 36673 bytes docs/tut/camera_mask.jpg | Bin 0 -> 18779 bytes docs/tut/camera_rgb.jpg | Bin 0 -> 32488 bytes docs/tut/camera_thresh.jpg | Bin 0 -> 4346 bytes docs/tut/camera_thresholded.jpg | Bin 0 -> 23678 bytes docs/tut/camera_yuv.jpg | Bin 0 -> 20105 bytes docs/tut/chimp.py.rst | 8 + docs/tut/chimpshot.gif | Bin 0 -> 46010 bytes docs/tut/common.txt | 8 + docs/tut/intro_ball.gif | Bin 0 -> 5015 bytes docs/tut/intro_blade.jpg | Bin 0 -> 2631 bytes docs/tut/intro_freedom.jpg | Bin 0 -> 7050 bytes docs/tut/newbieguide.rst | 494 ++++ docs/tut/surfarray.png | Bin 0 -> 50836 bytes docs/tut/surfarray_allblack.png | Bin 0 -> 125 bytes docs/tut/surfarray_flipped.png | Bin 0 -> 50835 bytes docs/tut/surfarray_redimg.png | Bin 0 -> 23443 bytes docs/tut/surfarray_rgbarray.png | Bin 0 -> 50897 bytes docs/tut/surfarray_scaledown.png | Bin 0 -> 15109 bytes docs/tut/surfarray_scaleup.png | Bin 0 -> 67759 bytes docs/tut/surfarray_soften.png | Bin 0 -> 47540 bytes docs/tut/surfarray_striped.png | Bin 0 -> 392 bytes docs/tut/surfarray_xfade.png | Bin 0 -> 41834 bytes docs/tut/tom_basic.png | Bin 0 -> 5139 bytes docs/tut/tom_event-flowchart.png | Bin 0 -> 5528 bytes docs/tut/tom_formulae.png | Bin 0 -> 6763 bytes docs/tut/tom_games2.rst | 135 ++ docs/tut/tom_games3.rst | 103 + docs/tut/tom_games4.rst | 143 ++ docs/tut/tom_games5.rst | 121 + docs/tut/tom_games6.rst | 330 +++ docs/tut/tom_radians.png | Bin 0 -> 17409 bytes 99 files changed, 23198 insertions(+), 51 deletions(-) create mode 100644 docs/c_api.rst create mode 100644 docs/common.txt create mode 100644 docs/filepaths.rst create mode 100644 docs/logos.rst create mode 100644 docs/ref/bufferproxy.rst create mode 100644 docs/ref/camera.rst create mode 100644 docs/ref/cdrom.rst create mode 100644 docs/ref/code_examples/angle_to.png create mode 100644 docs/ref/code_examples/base_script.py create mode 100644 docs/ref/code_examples/base_script_example.py create mode 100644 docs/ref/code_examples/cursors_module_example.py create mode 100644 docs/ref/code_examples/draw_module_example.png create mode 100644 docs/ref/code_examples/draw_module_example.py create mode 100644 docs/ref/code_examples/joystick_calls.png create mode 100644 docs/ref/color.rst create mode 100644 docs/ref/color_list.rst create mode 100644 docs/ref/common.txt create mode 100644 docs/ref/cursors.rst create mode 100644 docs/ref/display.rst create mode 100644 docs/ref/draw.rst create mode 100644 docs/ref/event.rst create mode 100644 docs/ref/examples.rst create mode 100644 docs/ref/fastevent.rst create mode 100644 docs/ref/font.rst create mode 100644 docs/ref/freetype.rst create mode 100644 docs/ref/gfxdraw.rst create mode 100644 docs/ref/image.rst create mode 100644 docs/ref/joystick.rst create mode 100644 docs/ref/key.rst create mode 100644 docs/ref/locals.rst create mode 100644 docs/ref/mask.rst create mode 100644 docs/ref/math.rst create mode 100644 docs/ref/midi.rst create mode 100644 docs/ref/mixer.rst create mode 100644 docs/ref/mouse.rst create mode 100644 docs/ref/music.rst create mode 100644 docs/ref/overlay.rst create mode 100644 docs/ref/pixelarray.rst create mode 100644 docs/ref/pixelcopy.rst create mode 100644 docs/ref/pygame.rst create mode 100644 docs/ref/rect.rst create mode 100644 docs/ref/scrap.rst create mode 100644 docs/ref/sdl2_controller.rst create mode 100644 docs/ref/sdl2_video.rst create mode 100644 docs/ref/sndarray.rst create mode 100644 docs/ref/sprite.rst create mode 100644 docs/ref/surface.rst create mode 100644 docs/ref/surfarray.rst create mode 100644 docs/ref/tests.rst create mode 100644 docs/ref/time.rst create mode 100644 docs/ref/touch.rst create mode 100644 docs/ref/transform.rst create mode 100644 docs/tut/CameraIntro.rst create mode 100644 docs/tut/ChimpLineByLine.rst create mode 100644 docs/tut/DisplayModes.rst create mode 100644 docs/tut/ImportInit.rst create mode 100644 docs/tut/MakeGames.rst create mode 100644 docs/tut/MoveIt.rst create mode 100644 docs/tut/PygameIntro.rst create mode 100644 docs/tut/SpriteIntro.rst create mode 100644 docs/tut/SurfarrayIntro-rest create mode 100644 docs/tut/SurfarrayIntro.rst create mode 100644 docs/tut/camera_average.jpg create mode 100644 docs/tut/camera_background.jpg create mode 100644 docs/tut/camera_green.jpg create mode 100644 docs/tut/camera_hsv.jpg create mode 100644 docs/tut/camera_mask.jpg create mode 100644 docs/tut/camera_rgb.jpg create mode 100644 docs/tut/camera_thresh.jpg create mode 100644 docs/tut/camera_thresholded.jpg create mode 100644 docs/tut/camera_yuv.jpg create mode 100644 docs/tut/chimp.py.rst create mode 100644 docs/tut/chimpshot.gif create mode 100644 docs/tut/common.txt create mode 100644 docs/tut/intro_ball.gif create mode 100644 docs/tut/intro_blade.jpg create mode 100644 docs/tut/intro_freedom.jpg create mode 100644 docs/tut/newbieguide.rst create mode 100644 docs/tut/surfarray.png create mode 100644 docs/tut/surfarray_allblack.png create mode 100644 docs/tut/surfarray_flipped.png create mode 100644 docs/tut/surfarray_redimg.png create mode 100644 docs/tut/surfarray_rgbarray.png create mode 100644 docs/tut/surfarray_scaledown.png create mode 100644 docs/tut/surfarray_scaleup.png create mode 100644 docs/tut/surfarray_soften.png create mode 100644 docs/tut/surfarray_striped.png create mode 100644 docs/tut/surfarray_xfade.png create mode 100644 docs/tut/tom_basic.png create mode 100644 docs/tut/tom_event-flowchart.png create mode 100644 docs/tut/tom_formulae.png create mode 100644 docs/tut/tom_games2.rst create mode 100644 docs/tut/tom_games3.rst create mode 100644 docs/tut/tom_games4.rst create mode 100644 docs/tut/tom_games5.rst create mode 100644 docs/tut/tom_games6.rst create mode 100644 docs/tut/tom_radians.png diff --git a/docs/c_api.rst b/docs/c_api.rst new file mode 100644 index 0000000..734289f --- /dev/null +++ b/docs/c_api.rst @@ -0,0 +1,25 @@ +pygame C API +============ + +.. toctree:: + :maxdepth: 1 + :glob: + + c_api/slots.rst + c_api/base.rst + c_api/bufferproxy.rst + c_api/color.rst + c_api/display.rst + c_api/event.rst + c_api/freetype.rst + c_api/mixer.rst + c_api/rect.rst + c_api/rwobject.rst + c_api/surface.rst + c_api/surflock.rst + c_api/version.rst + + +src_c/include/ contains header files for applications +that use the pygame C API, while src_c/ contains +headers used by pygame internally. diff --git a/docs/common.txt b/docs/common.txt new file mode 100644 index 0000000..e3a2f46 --- /dev/null +++ b/docs/common.txt @@ -0,0 +1,14 @@ +.. Pygame specific reST elements. + +.. role:: summaryline + +.. role:: sl(summaryline) + :class: summaryline + +.. role:: signature + +.. role:: sg(signature) + :class: signature + +.. role:: small-heading + :class: small-heading diff --git a/docs/conf.py b/docs/conf.py index df6cead..9c80867 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,44 +1,228 @@ -# Configuration file for the Sphinx documentation builder. - -# -- Project information -import sys -import os -sys.path.insert(0, os.path.abspath('..')) - -project = 'Masterchicken' -copyright = '2023, Masterchicken developers' -author = 'PythonChicken123' - -release = '0.1' -version = '0.0.7' - -# -- General configuration - -extensions = [ - 'sphinx.ext.duration', - 'sphinx.ext.doctest', - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.intersphinx', - 'sphinx.ext.coverage', - 'ext.headers', - 'ext.boilerplate', - 'ext.customversion', - 'ext.edit_on_github' -] +# +# Pygame documentation build configuration file, created by +# sphinx-quickstart on Sat Mar 5 11:56:39 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. -intersphinx_mapping = { - 'python': ('https://docs.python.org/3/', None), - 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), -} -intersphinx_disabled_domains = ['std'] -pygments_style = 'sphinx' -modindex_common_prefix = ['masterchicken'] +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', + 'sphinx.ext.coverage', 'ext.headers', 'ext.boilerplate', + 'ext.customversion', 'ext.edit_on_github'] + + +# Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# -- Options for HTML output +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pygame' +copyright = '2000-2023, pygame developers' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.6.0' +# The full version, including alpha/beta/rc tags. +release = '2.6.0.dev1' + +# Format strings for the version directives +versionadded_format = 'New in pygame %s' +versionchanged_format = 'Changed in pygame %s' +deprecated_format = 'Deprecated since pygame %s' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +#exclude_trees = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +modindex_common_prefix = ['pygame'] + +# Documents which are to be left undecorated +# (e.g. adding tooltips to known document links): +boilerplate_skip_transform = ['index'] + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'classic' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = {'home_uri': 'https://www.pygame.org/'} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['themes'] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = f"{project} v{version} documentation" + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = '_static/pygame_tiny.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = '_static/pygame.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra files that should be included in the build. +html_extra_path = ['../LGPL.txt'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Pygamedoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Pygame.tex', 'Pygame Documentation', + 'Pygame Developers', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True + +#-- Options for C header output ------------------------------------------------ + +# Target directory for header files (default: current working directory). +headers_dest = './_headers' + +# Whether or not to create target directory tree if it does not exist +# (default: no directory creation). +headers_mkdirs = True + +# Suffix to add for header file names before the '.h' extension +# (default: no suffix). +headers_filename_sfx = '_doc' -html_theme = "classic" +smartquotes = False -# -- Options for EPUB output -epub_show_urls = 'footnote' +edit_on_github_project = 'pygame/pygame' +edit_on_github_branch = 'main' diff --git a/docs/filepaths.rst b/docs/filepaths.rst new file mode 100644 index 0000000..e17f687 --- /dev/null +++ b/docs/filepaths.rst @@ -0,0 +1,17 @@ +File Path Function Arguments +============================ + +A pygame function or method which takes a file path argument will accept +either a Unicode or a byte (8-bit or ASCII character) string. +Unicode strings are translated to Python's default filesystem encoding, +as returned by sys.getfilesystemencoding(). A Unicode code point +above U+FFFF (``\uFFFF``) can be coded directly with a 32-bit escape sequences +(``\Uxxxxxxxx``), even for Python interpreters built with an UCS-2 +(16-bit character) Unicode type. Byte strings are passed +to the operating system unchanged. + +Null characters (``\x00``) are not permitted in the path, raising an exception. +An exception is also raised if an Unicode file path cannot be encoded. +How UTF-16 surrogate codes are handled is Python-interpreter-dependent. +Use UTF-32 code points and 32-bit escape sequences instead. +The exception types are function-dependent. diff --git a/docs/index.rst b/docs/index.rst index dd6497e..8d34d7c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,19 +1,213 @@ -Welcome to Masterchicken's documentation! -=================================== +Pygame Front Page +================= -**Masterchicken** (/lu'make/) is a Python library to speed up code and imports an optimized csv reader/writer, this CSV reader can read and print a 100,000 lined CSV file in a maxiumum of 7 seconds. +.. toctree:: + :maxdepth: 2 + :glob: + :hidden: -Check out the :doc:`usage` section for further information, including -how to :ref:`installation` the project. + ref/* + tut/* + tut/en/**/* + tut/ko/**/* + c_api + filepaths + logos -.. note:: +Quick start +----------- - This project is under active development. +Welcome to pygame! Once you've got pygame installed (:code:`pip install pygame` or +:code:`pip3 install pygame` for most people), the next question is how to get a game +loop running. Pygame, unlike some other libraries, gives you full control of program +execution. That freedom means it is easy to mess up in your initial steps. -Contents --------- +Here is a good example of a basic setup (opens the window, updates the screen, and handles events)-- -.. toctree:: +.. literalinclude:: ref/code_examples/base_script.py + +Here is a slightly more fleshed out example, which shows you how to move something +(a circle in this case) around on screen-- + +.. literalinclude:: ref/code_examples/base_script_example.py + +For more in depth reference, check out the :ref:`tutorials-reference-label` +section below, check out a video tutorial (`I'm a fan of this one +`_), or reference the API +documentation by module. + +Documents +--------- + +`Readme`_ + Basic information about pygame: what it is, who is involved, and where to find it. + +`Install`_ + Steps needed to compile pygame on several platforms. + Also help on finding and installing prebuilt binaries for your system. + +:doc:`filepaths` + How pygame handles file system paths. + +:doc:`Pygame Logos ` + The logos of Pygame in different resolutions. + + +`LGPL License`_ + This is the license pygame is distributed under. + It provides for pygame to be distributed with open source and commercial software. + Generally, if pygame is not changed, it can be used with any type of program. + +.. _tutorials-reference-label: + +Tutorials +--------- + +:doc:`Introduction to Pygame ` + An introduction to the basics of pygame. + This is written for users of Python and appeared in volume two of the Py magazine. + +:doc:`Import and Initialize ` + The beginning steps on importing and initializing pygame. + The pygame package is made of several modules. + Some modules are not included on all platforms. + +:doc:`How do I move an Image? ` + A basic tutorial that covers the concepts behind 2D computer animation. + Information about drawing and clearing objects to make them appear animated. + +:doc:`Chimp Tutorial, Line by Line ` + The pygame examples include a simple program with an interactive fist and a chimpanzee. + This was inspired by the annoying flash banner of the early 2000s. + This tutorial examines every line of code used in the example. + +:doc:`Sprite Module Introduction ` + Pygame includes a higher level sprite module to help organize games. + The sprite module includes several classes that help manage details found in almost all games types. + The Sprite classes are a bit more advanced than the regular pygame modules, + and need more understanding to be properly used. + +:doc:`Surfarray Introduction ` + Pygame used the NumPy python module to allow efficient per pixel effects on images. + Using the surface arrays is an advanced feature that allows custom effects and filters. + This also examines some of the simple effects from the pygame example, arraydemo.py. + +:doc:`Camera Module Introduction ` + Pygame, as of 1.9, has a camera module that allows you to capture images, + watch live streams, and do some basic computer vision. + This tutorial covers those use cases. + +:doc:`Newbie Guide ` + A list of thirteen helpful tips for people to get comfortable using pygame. + +:doc:`Making Games Tutorial ` + A large tutorial that covers the bigger topics needed to create an entire game. + +:doc:`Display Modes ` + Getting a display surface for the screen. + +:doc:`한국어 튜토리얼 (Korean Tutorial) ` + 빨간블록 검은블록 + + +Reference +--------- + +:ref:`genindex` + A list of all functions, classes, and methods in the pygame package. + +:doc:`ref/bufferproxy` + An array protocol view of surface pixels + +:doc:`ref/color` + Color representation. + +:doc:`ref/cursors` + Loading and compiling cursor images. + +:doc:`ref/display` + Configure the display surface. + +:doc:`ref/draw` + Drawing simple shapes like lines and ellipses to surfaces. + +:doc:`ref/event` + Manage the incoming events from various input devices and the windowing platform. + +:doc:`ref/examples` + Various programs demonstrating the use of individual pygame modules. + +:doc:`ref/font` + Loading and rendering TrueType fonts. + +:doc:`ref/freetype` + Enhanced pygame module for loading and rendering font faces. + +:doc:`ref/gfxdraw` + Anti-aliasing draw functions. + +:doc:`ref/image` + Loading, saving, and transferring of surfaces. + +:doc:`ref/joystick` + Manage the joystick devices. + +:doc:`ref/key` + Manage the keyboard device. + +:doc:`ref/locals` + Pygame constants. + +:doc:`ref/mixer` + Load and play sounds + +:doc:`ref/mouse` + Manage the mouse device and display. + +:doc:`ref/music` + Play streaming music tracks. + +:doc:`ref/pygame` + Top level functions to manage pygame. + +:doc:`ref/pixelarray` + Manipulate image pixel data. + +:doc:`ref/rect` + Flexible container for a rectangle. + +:doc:`ref/scrap` + Native clipboard access. + +:doc:`ref/sndarray` + Manipulate sound sample data. + +:doc:`ref/sprite` + Higher level objects to represent game images. + +:doc:`ref/surface` + Objects for images and the screen. + +:doc:`ref/surfarray` + Manipulate image pixel data. + +:doc:`ref/tests` + Test pygame. + +:doc:`ref/time` + Manage timing and framerate. + +:doc:`ref/transform` + Resize and move images. + +:doc:`pygame C API ` + The C api shared amongst pygame extension modules. + +:ref:`search` + Search pygame documents by keyword. + +.. _Readme: ../wiki/about + +.. _Install: ../wiki/GettingStarted#Pygame%20Installation - usage - api +.. _LGPL License: LGPL.txt diff --git a/docs/logos.rst b/docs/logos.rst new file mode 100644 index 0000000..a7ee493 --- /dev/null +++ b/docs/logos.rst @@ -0,0 +1,47 @@ +************************************************* + Pygame Logos Page +************************************************* + +Pygame Logos +============ + +These logos are available for use in your own game projects. +Please put them up wherever you see fit. The logo was created +by TheCorruptor on July 29, 2001 and upscaled by Mega_JC on +August 29, 2021. + +.. container:: fullwidth + + .. image:: _static/pygame_logo.png + + | `pygame_logo.svg <_static/pygame_logo.svg>`_ + | `pygame_logo.png <_static/pygame_logo.png>`_ - 1561 x 438 + + .. image:: _static/pygame_lofi.png + + | `pygame_lofi.svg <_static/pygame_lofi.svg>`_ + | `pygame_lofi.png <_static/pygame_lofi.png>`_ - 1561 x 438 + + .. image:: _static/pygame_powered.png + + | `pygame_powered.svg <_static/pygame_powered.svg>`_ + | `pygame_powered.png <_static/pygame_powered.png>`_ - 1617 x 640 + + .. image:: _static/pygame_tiny.png + + | `pygame_tiny.png <_static/pygame_tiny.png>`_ - 214 x 60 + + .. image:: _static/pygame_powered_lowres.png + + | `pygame_powered_lowres.png <_static/pygame_powered_lowres.png>`_ - 101 x 40 + + +There is a higher resolution layered photoshop image +available `here `_. *(1.3 MB)* + +Legacy logos +------------ + +.. container:: fullwidth + + `legacy_logos.zip <_static/legacy_logos.zip>`_ - 50.1 KB \ No newline at end of file diff --git a/docs/ref/bufferproxy.rst b/docs/ref/bufferproxy.rst new file mode 100644 index 0000000..bb4e693 --- /dev/null +++ b/docs/ref/bufferproxy.rst @@ -0,0 +1,113 @@ +.. include:: common.txt + +.. default-domain:: py + +:class:`pygame.BufferProxy` +=========================== + +.. currentmodule:: pygame + +.. class:: BufferProxy + + | :sl:`pygame object to export a surface buffer through an array protocol` + | :sg:`BufferProxy() -> BufferProxy` + + :class:`BufferProxy` is a pygame support type, designed as the return value + of the :meth:`Surface.get_buffer` and :meth:`Surface.get_view` methods. + For all Python versions a :class:`BufferProxy` object exports a C struct + and Python level array interface on behalf of its parent object's buffer. + A new buffer interface is also exported. + In pygame, :class:`BufferProxy` is key to implementing the + :mod:`pygame.surfarray` module. + + :class:`BufferProxy` instances can be created directly from Python code, + either for a parent that exports an interface, or from a Python ``dict`` + describing an object's buffer layout. The dict entries are based on the + Python level array interface mapping. The following keys are recognized: + + ``"shape"`` : tuple + The length of each array dimension as a tuple of integers. The + length of the tuple is the number of dimensions in the array. + + ``"typestr"`` : string + The array element type as a length 3 string. The first character + gives byteorder, '<' for little-endian, '>' for big-endian, and + '\|' for not applicable. The second character is the element type, + 'i' for signed integer, 'u' for unsigned integer, 'f' for floating + point, and 'V' for an chunk of bytes. The third character gives the + bytesize of the element, from '1' to '9' bytes. So, for example, + " Surface` + | :sg:`parent -> ` + + The :class:`Surface` which returned the :class:`BufferProxy` object or + the object passed to a :class:`BufferProxy` call. + + .. attribute:: length + + | :sl:`The size, in bytes, of the exported buffer.` + | :sg:`length -> int` + + The number of valid bytes of data exported. For discontinuous data, + that is data which is not a single block of memory, the bytes within + the gaps are excluded from the count. This property is equivalent to + the ``Py_buffer`` C struct ``len`` field. + + .. attribute:: raw + + | :sl:`A copy of the exported buffer as a single block of bytes.` + | :sg:`raw -> bytes` + + The buffer data as a ``str``/``bytes`` object. + Any gaps in the exported data are removed. + + .. method:: write + + | :sl:`Write raw bytes to object buffer.` + | :sg:`write(buffer, offset=0)` + + Overwrite bytes in the parent object's data. The data must be C or F + contiguous, otherwise a ValueError is raised. Argument `buffer` is a + ``str``/``bytes`` object. An optional offset gives a + start position, in bytes, within the buffer where overwriting begins. + If the offset is negative or greater that or equal to the buffer proxy's + :attr:`length` value, an ``IndexException`` is raised. + If ``len(buffer) > proxy.length + offset``, a ``ValueError`` is raised. diff --git a/docs/ref/camera.rst b/docs/ref/camera.rst new file mode 100644 index 0000000..a412392 --- /dev/null +++ b/docs/ref/camera.rst @@ -0,0 +1,250 @@ +.. include:: common.txt + +:mod:`pygame.camera` +==================== + +.. module:: pygame.camera + :synopsis: pygame module for camera use + +| :sl:`pygame module for camera use` + +.. note:: + Use import pygame.camera before using this module. + +Pygame currently supports Linux (V4L2) and Windows (MSMF) cameras natively, +with wider platform support available via an integrated OpenCV backend. + +.. versionadded:: 2.0.2 Windows native camera support +.. versionadded:: 2.0.3 New OpenCV backends + +EXPERIMENTAL!: This API may change or disappear in later pygame releases. If +you use this, your code will very likely break with the next pygame release. + +The Bayer to ``RGB`` function is based on: + +:: + + Sonix SN9C101 based webcam basic I/F routines + Copyright (C) 2004 Takafumi Mizuno + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +New in pygame 1.9.0. + +.. function:: init + + | :sl:`Module init` + | :sg:`init(backend = None) -> None` + + This function starts up the camera module, choosing the best webcam backend + it can find for your system. This is not guaranteed to succeed, and may even + attempt to import third party modules, like `OpenCV`. If you want to + override its backend choice, you can call pass the name of the backend you + want into this function. More about backends in + :func:`get_backends()`. + + .. versionchanged:: 2.0.3 Option to explicitly select backend + + .. ## pygame.camera.init ## + +.. function:: get_backends + + | :sl:`Get the backends supported on this system` + | :sg:`get_backends() -> [str]` + + This function returns every backend it thinks has a possibility of working + on your system, in order of priority. + + pygame.camera Backends: + :: + + Backend OS Description + --------------------------------------------------------------------------------- + _camera (MSMF) Windows Builtin, works on Windows 8+ Python3 + _camera (V4L2) Linux Builtin + OpenCV Any Uses `opencv-python` module, can't enumerate cameras + OpenCV-Mac Mac Same as OpenCV, but has camera enumeration + VideoCapture Windows Uses abandoned `VideoCapture` module, can't enumerate + cameras, may be removed in the future + + There are two main differences among backends. + + The _camera backends are built in to pygame itself, and require no third + party imports. All the other backends do. For the OpenCV and VideoCapture + backends, those modules need to be installed on your system. + + The other big difference is "camera enumeration." Some backends don't have + a way to list out camera names, or even the number of cameras on the + system. In these cases, :func:`list_cameras()` will return + something like ``[0]``. If you know you have multiple cameras on the + system, these backend ports will pass through a "camera index number" + through if you use that as the ``device`` parameter. + + .. versionadded:: 2.0.3 + + .. ## pygame.camera.get_backends ## + +.. function:: colorspace + + | :sl:`Surface colorspace conversion` + | :sg:`colorspace(Surface, format, DestSurface = None) -> Surface` + + Allows for conversion from "RGB" to a destination colorspace of "HSV" or + "YUV". The source and destination surfaces must be the same size and pixel + depth. This is useful for computer vision on devices with limited processing + power. Capture as small of an image as possible, ``transform.scale()`` it + even smaller, and then convert the colorspace to ``YUV`` or ``HSV`` before + doing any processing on it. + + .. ## pygame.camera.colorspace ## + +.. function:: list_cameras + + | :sl:`returns a list of available cameras` + | :sg:`list_cameras() -> [cameras]` + + Checks the computer for available cameras and returns a list of strings of + camera names, ready to be fed into :class:`pygame.camera.Camera`. + + If the camera backend doesn't support webcam enumeration, this will return + something like ``[0]``. See :func:`get_backends()` for much more + information. + + .. ## pygame.camera.list_cameras ## + +.. class:: Camera + + | :sl:`load a camera` + | :sg:`Camera(device, (width, height), format) -> Camera` + + Loads a camera. On Linux, the device is typically something like + "/dev/video0". Default width and height are 640 by 480. + Format is the desired colorspace of the output. + This is useful for computer vision purposes. The default is + ``RGB``. The following are supported: + + * ``RGB`` - Red, Green, Blue + + * ``YUV`` - Luma, Blue Chrominance, Red Chrominance + + * ``HSV`` - Hue, Saturation, Value + + .. method:: start + + | :sl:`opens, initializes, and starts capturing` + | :sg:`start() -> None` + + Opens the camera device, attempts to initialize it, and begins recording + images to a buffer. The camera must be started before any of the below + functions can be used. + + .. ## Camera.start ## + + .. method:: stop + + | :sl:`stops, uninitializes, and closes the camera` + | :sg:`stop() -> None` + + Stops recording, uninitializes the camera, and closes it. Once a camera + is stopped, the below functions cannot be used until it is started again. + + .. ## Camera.stop ## + + .. method:: get_controls + + | :sl:`gets current values of user controls` + | :sg:`get_controls() -> (hflip = bool, vflip = bool, brightness)` + + If the camera supports it, get_controls will return the current settings + for horizontal and vertical image flip as bools and brightness as an int. + If unsupported, it will return the default values of (0, 0, 0). Note that + the return values here may be different than those returned by + set_controls, though these are more likely to be correct. + + .. ## Camera.get_controls ## + + .. method:: set_controls + + | :sl:`changes camera settings if supported by the camera` + | :sg:`set_controls(hflip = bool, vflip = bool, brightness) -> (hflip = bool, vflip = bool, brightness)` + + Allows you to change camera settings if the camera supports it. The + return values will be the input values if the camera claims it succeeded + or the values previously in use if not. Each argument is optional, and + the desired one can be chosen by supplying the keyword, like hflip. Note + that the actual settings being used by the camera may not be the same as + those returned by set_controls. On Windows, :code:`hflip` and :code:`vflip` are + implemented by pygame, not by the Camera, so they should always work, but + :code:`brightness` is unsupported. + + .. ## Camera.set_controls ## + + .. method:: get_size + + | :sl:`returns the dimensions of the images being recorded` + | :sg:`get_size() -> (width, height)` + + Returns the current dimensions of the images being captured by the + camera. This will return the actual size, which may be different than the + one specified during initialization if the camera did not support that + size. + + .. ## Camera.get_size ## + + .. method:: query_image + + | :sl:`checks if a frame is ready` + | :sg:`query_image() -> bool` + + If an image is ready to get, it returns true. Otherwise it returns false. + Note that some webcams will always return False and will only queue a + frame when called with a blocking function like :func:`get_image()`. + On Windows (MSMF), and the OpenCV backends, :func:`query_image()` + should be reliable, though. This is useful to separate the framerate of + the game from that of the camera without having to use threading. + + .. ## Camera.query_image ## + + .. method:: get_image + + | :sl:`captures an image as a Surface` + | :sg:`get_image(Surface = None) -> Surface` + + Pulls an image off of the buffer as an ``RGB`` Surface. It can optionally + reuse an existing Surface to save time. The bit-depth of the surface is + 24 bits on Linux, 32 bits on Windows, or the same as the optionally + supplied Surface. + + .. ## Camera.get_image ## + + .. method:: get_raw + + | :sl:`returns an unmodified image as bytes` + | :sg:`get_raw() -> bytes` + + Gets an image from a camera as a string in the native pixelformat of the + camera. Useful for integration with other libraries. This returns a + bytes object + + .. ## Camera.get_raw ## + + .. ## pygame.camera.Camera ## + +.. ## pygame.camera ## diff --git a/docs/ref/cdrom.rst b/docs/ref/cdrom.rst new file mode 100644 index 0000000..62688c9 --- /dev/null +++ b/docs/ref/cdrom.rst @@ -0,0 +1,310 @@ +.. include:: common.txt + +:mod:`pygame.cdrom` +=================== + +.. module:: pygame.cdrom + :synopsis: pygame module for audio cdrom control + +| :sl:`pygame module for audio cdrom control` + +.. warning:: + This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. + This module will not be supported in the future. + One alternative for python cdrom functionality is `pycdio `_. + +The cdrom module manages the ``CD`` and ``DVD`` drives on a computer. It can +also control the playback of audio CDs. This module needs to be initialized +before it can do anything. Each ``CD`` object you create represents a cdrom +drive and must also be initialized individually before it can do most things. + +.. function:: init + + | :sl:`initialize the cdrom module` + | :sg:`init() -> None` + + Initialize the cdrom module. This will scan the system for all ``CD`` + devices. The module must be initialized before any other functions will + work. This automatically happens when you call ``pygame.init()``. + + It is safe to call this function more than once. + + .. ## pygame.cdrom.init ## + +.. function:: quit + + | :sl:`uninitialize the cdrom module` + | :sg:`quit() -> None` + + Uninitialize the cdrom module. After you call this any existing ``CD`` + objects will no longer work. + + It is safe to call this function more than once. + + .. ## pygame.cdrom.quit ## + +.. function:: get_init + + | :sl:`true if the cdrom module is initialized` + | :sg:`get_init() -> bool` + + Test if the cdrom module is initialized or not. This is different than the + ``CD.init()`` since each drive must also be initialized individually. + + .. ## pygame.cdrom.get_init ## + +.. function:: get_count + + | :sl:`number of cd drives on the system` + | :sg:`get_count() -> count` + + Return the number of cd drives on the system. When you create ``CD`` objects + you need to pass an integer id that must be lower than this count. The count + will be 0 if there are no drives on the system. + + .. ## pygame.cdrom.get_count ## + +.. class:: CD + + | :sl:`class to manage a cdrom drive` + | :sg:`CD(id) -> CD` + + You can create a ``CD`` object for each cdrom on the system. Use + ``pygame.cdrom.get_count()`` to determine how many drives actually exist. + The id argument is an integer of the drive, starting at zero. + + The ``CD`` object is not initialized, you can only call ``CD.get_id()`` and + ``CD.get_name()`` on an uninitialized drive. + + It is safe to create multiple ``CD`` objects for the same drive, they will + all cooperate normally. + + .. method:: init + + | :sl:`initialize a cdrom drive for use` + | :sg:`init() -> None` + + Initialize the cdrom drive for use. The drive must be initialized for + most ``CD`` methods to work. Even if the rest of pygame has been + initialized. + + There may be a brief pause while the drive is initialized. Avoid + ``CD.init()`` if the program should not stop for a second or two. + + .. ## CD.init ## + + .. method:: quit + + | :sl:`uninitialize a cdrom drive for use` + | :sg:`quit() -> None` + + Uninitialize a drive for use. Call this when your program will not be + accessing the drive for awhile. + + .. ## CD.quit ## + + .. method:: get_init + + | :sl:`true if this cd device initialized` + | :sg:`get_init() -> bool` + + Test if this ``CDROM`` device is initialized. This is different than the + ``pygame.cdrom.init()`` since each drive must also be initialized + individually. + + .. ## CD.get_init ## + + .. method:: play + + | :sl:`start playing audio` + | :sg:`play(track, start=None, end=None) -> None` + + Playback audio from an audio cdrom in the drive. Besides the track number + argument, you can also pass a starting and ending time for playback. The + start and end time are in seconds, and can limit the section of an audio + track played. + + If you pass a start time but no end, the audio will play to the end of + the track. If you pass a start time and 'None' for the end time, the + audio will play to the end of the entire disc. + + See the ``CD.get_numtracks()`` and ``CD.get_track_audio()`` to find + tracks to playback. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.play ## + + .. method:: stop + + | :sl:`stop audio playback` + | :sg:`stop() -> None` + + Stops playback of audio from the cdrom. This will also lose the current + playback position. This method does nothing if the drive isn't already + playing audio. + + .. ## CD.stop ## + + .. method:: pause + + | :sl:`temporarily stop audio playback` + | :sg:`pause() -> None` + + Temporarily stop audio playback on the ``CD``. The playback can be + resumed at the same point with the ``CD.resume()`` method. If the ``CD`` + is not playing this method does nothing. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.pause ## + + .. method:: resume + + | :sl:`unpause audio playback` + | :sg:`resume() -> None` + + Unpause a paused ``CD``. If the ``CD`` is not paused or already playing, + this method does nothing. + + .. ## CD.resume ## + + .. method:: eject + + | :sl:`eject or open the cdrom drive` + | :sg:`eject() -> None` + + This will open the cdrom drive and eject the cdrom. If the drive is + playing or paused it will be stopped. + + .. ## CD.eject ## + + .. method:: get_id + + | :sl:`the index of the cdrom drive` + | :sg:`get_id() -> id` + + Returns the integer id that was used to create the ``CD`` instance. This + method can work on an uninitialized ``CD``. + + .. ## CD.get_id ## + + .. method:: get_name + + | :sl:`the system name of the cdrom drive` + | :sg:`get_name() -> name` + + Return the string name of the drive. This is the system name used to + represent the drive. It is often the drive letter or device name. This + method can work on an uninitialized ``CD``. + + .. ## CD.get_name ## + + .. method:: get_busy + + | :sl:`true if the drive is playing audio` + | :sg:`get_busy() -> bool` + + Returns True if the drive busy playing back audio. + + .. ## CD.get_busy ## + + .. method:: get_paused + + | :sl:`true if the drive is paused` + | :sg:`get_paused() -> bool` + + Returns True if the drive is currently paused. + + .. ## CD.get_paused ## + + .. method:: get_current + + | :sl:`the current audio playback position` + | :sg:`get_current() -> track, seconds` + + Returns both the current track and time of that track. This method works + when the drive is either playing or paused. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_current ## + + .. method:: get_empty + + | :sl:`False if a cdrom is in the drive` + | :sg:`get_empty() -> bool` + + Return False if there is a cdrom currently in the drive. If the drive is + empty this will return True. + + .. ## CD.get_empty ## + + .. method:: get_numtracks + + | :sl:`the number of tracks on the cdrom` + | :sg:`get_numtracks() -> count` + + Return the number of tracks on the cdrom in the drive. This will return + zero of the drive is empty or has no tracks. + + .. ## CD.get_numtracks ## + + .. method:: get_track_audio + + | :sl:`true if the cdrom track has audio data` + | :sg:`get_track_audio(track) -> bool` + + Determine if a track on a cdrom contains audio data. You can also call + ``CD.num_tracks()`` and ``CD.get_all()`` to determine more information + about the cdrom. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_audio ## + + .. method:: get_all + + | :sl:`get all track information` + | :sg:`get_all() -> [(audio, start, end, length), ...]` + + Return a list with information for every track on the cdrom. The + information consists of a tuple with four values. The audio value is True + if the track contains audio data. The start, end, and length values are + floating point numbers in seconds. Start and end represent absolute times + on the entire disc. + + .. ## CD.get_all ## + + .. method:: get_track_start + + | :sl:`start time of a cdrom track` + | :sg:`get_track_start(track) -> seconds` + + Return the absolute time in seconds where at start of the cdrom track. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_start ## + + .. method:: get_track_length + + | :sl:`length of a cdrom track` + | :sg:`get_track_length(track) -> seconds` + + Return a floating point value in seconds of the length of the cdrom + track. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_length ## + + .. ## pygame.cdrom.CD ## + +.. ## pygame.cdrom ## diff --git a/docs/ref/code_examples/angle_to.png b/docs/ref/code_examples/angle_to.png new file mode 100644 index 0000000000000000000000000000000000000000..2cf3b2a546a61e060510212b079d0fc4a6efaa80 GIT binary patch literal 25349 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 L`njxgN@xNAeMj~* literal 0 HcmV?d00001 diff --git a/docs/ref/code_examples/base_script.py b/docs/ref/code_examples/base_script.py new file mode 100644 index 0000000..c1cd142 --- /dev/null +++ b/docs/ref/code_examples/base_script.py @@ -0,0 +1,27 @@ +# Example file showing a basic pygame "game loop" +import pygame + +# pygame setup +pygame.init() +screen = pygame.display.set_mode((1280, 720)) +clock = pygame.time.Clock() +running = True + +while running: + # poll for events + # pygame.QUIT event means the user clicked X to close your window + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # fill the screen with a color to wipe away anything from last frame + screen.fill("purple") + + # RENDER YOUR GAME HERE + + # flip() the display to put your work on screen + pygame.display.flip() + + clock.tick(60) # limits FPS to 60 + +pygame.quit() diff --git a/docs/ref/code_examples/base_script_example.py b/docs/ref/code_examples/base_script_example.py new file mode 100644 index 0000000..0fac3f6 --- /dev/null +++ b/docs/ref/code_examples/base_script_example.py @@ -0,0 +1,43 @@ +# Example file showing a circle moving on screen +import pygame + +# pygame setup +pygame.init() +screen = pygame.display.set_mode((1280, 720)) +clock = pygame.time.Clock() +running = True +dt = 0 + +player_pos = pygame.Vector2(screen.get_width() / 2, screen.get_height() / 2) + +while running: + # poll for events + # pygame.QUIT event means the user clicked X to close your window + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # fill the screen with a color to wipe away anything from last frame + screen.fill("purple") + + pygame.draw.circle(screen, "red", player_pos, 40) + + keys = pygame.key.get_pressed() + if keys[pygame.K_w]: + player_pos.y -= 300 * dt + if keys[pygame.K_s]: + player_pos.y += 300 * dt + if keys[pygame.K_a]: + player_pos.x -= 300 * dt + if keys[pygame.K_d]: + player_pos.x += 300 * dt + + # flip() the display to put your work on screen + pygame.display.flip() + + # limits FPS to 60 + # dt is delta time in seconds since last frame, used for framerate- + # independent physics. + dt = clock.tick(60) / 1000 + +pygame.quit() diff --git a/docs/ref/code_examples/cursors_module_example.py b/docs/ref/code_examples/cursors_module_example.py new file mode 100644 index 0000000..95fa6a4 --- /dev/null +++ b/docs/ref/code_examples/cursors_module_example.py @@ -0,0 +1,44 @@ +# pygame setup +import pygame as pg + +pg.init() +screen = pg.display.set_mode([600, 400]) +pg.display.set_caption("Example code for the cursors module") + +# create a system cursor +system = pg.cursors.Cursor(pg.SYSTEM_CURSOR_NO) + +# create bitmap cursors +bitmap_1 = pg.cursors.Cursor(*pg.cursors.arrow) +bitmap_2 = pg.cursors.Cursor( + (24, 24), (0, 0), *pg.cursors.compile(pg.cursors.thickarrow_strings) +) + +# create a color cursor +surf = pg.Surface((40, 40)) # you could also load an image +surf.fill((120, 50, 50)) # and use that as your surface +color = pg.cursors.Cursor((20, 20), surf) + +cursors = [system, bitmap_1, bitmap_2, color] +cursor_index = 0 + +pg.mouse.set_cursor(cursors[cursor_index]) + +clock = pg.time.Clock() +going = True +while going: + clock.tick(60) + screen.fill((0, 75, 30)) + pg.display.flip() + + for event in pg.event.get(): + if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE): + going = False + + # if the mouse is clicked it will switch to a new cursor + if event.type == pg.MOUSEBUTTONDOWN: + cursor_index += 1 + cursor_index %= len(cursors) + pg.mouse.set_cursor(cursors[cursor_index]) + +pg.quit() diff --git a/docs/ref/code_examples/draw_module_example.png b/docs/ref/code_examples/draw_module_example.png new file mode 100644 index 0000000000000000000000000000000000000000..42d6ed183113884b80efbef261eaa278eeba9fb3 GIT binary patch literal 6476 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 Color` + | :sg:`Color(r, g, b, a=255) -> Color` + | :sg:`Color(color_value) -> Color` + + The ``Color`` class represents ``RGBA`` color values using a value range of + 0 to 255 inclusive. It allows basic arithmetic operations — binary + operations ``+``, ``-``, ``*``, ``//``, ``%``, and unary operation ``~`` — to + create new colors, supports conversions to other color spaces such as ``HSV`` + or ``HSL`` and lets you adjust single color channels. + Alpha defaults to 255 (fully opaque) when not given. + The arithmetic operations and ``correct_gamma()`` method preserve subclasses. + For the binary operators, the class of the returned color is that of the + left hand color object of the operator. + + Color objects support equality comparison with other color objects and 3 or + 4 element tuples of integers. There was a bug in pygame 1.8.1 + where the default alpha was 0, not 255 like previously. + + Color objects export the C level array interface. The interface exports a + read-only one dimensional unsigned byte array of the same assigned length + as the color. The new buffer interface is also exported, with the same + characteristics as the array interface. + + The floor division, ``//``, and modulus, ``%``, operators do not raise + an exception for division by zero. Instead, if a color, or alpha, channel + in the right hand color is 0, then the result is 0. For example: :: + + # These expressions are True + Color(255, 255, 255, 255) // Color(0, 64, 64, 64) == Color(0, 3, 3, 3) + Color(255, 255, 255, 255) % Color(64, 64, 64, 0) == Color(63, 63, 63, 0) + + Use ``int(color)`` to return the immutable integer value of the color, + usable as a ``dict`` key. This integer value differs from the mapped + pixel values of :meth:`pygame.Surface.get_at_mapped`, + :meth:`pygame.Surface.map_rgb` and :meth:`pygame.Surface.unmap_rgb`. + It can be passed as a ``color_value`` argument to :class:`Color` + (useful with sets). + + See :doc:`color_list` for samples of the available named colors. + + :param int r: red value in the range of 0 to 255 inclusive + :param int g: green value in the range of 0 to 255 inclusive + :param int b: blue value in the range of 0 to 255 inclusive + :param int a: (optional) alpha value in the range of 0 to 255 inclusive, + default is 255 + :param color_value: color value (see note below for the supported formats) + + .. note:: + Supported ``color_value`` formats: + | - **Color object:** clones the given :class:`Color` object + | - **Color name: str:** name of the color to use, e.g. ``'red'`` + (all the supported name strings can be found in the + :doc:`color_list`, with sample swatches) + | - **HTML color format str:** ``'#rrggbbaa'`` or ``'#rrggbb'``, + where rr, gg, bb, and aa are 2-digit hex numbers in the range + of 0 to 0xFF inclusive, the aa (alpha) value defaults to 0xFF + if not provided + | - **hex number str:** ``'0xrrggbbaa'`` or ``'0xrrggbb'``, where + rr, gg, bb, and aa are 2-digit hex numbers in the range of 0x00 + to 0xFF inclusive, the aa (alpha) value defaults to 0xFF if not + provided + | - **int:** int value of the color to use, using hex numbers can + make this parameter more readable, e.g. ``0xrrggbbaa``, where rr, + gg, bb, and aa are 2-digit hex numbers in the range of 0x00 to + 0xFF inclusive, note that the aa (alpha) value is not optional for + the int format and must be provided + | - **tuple/list of int color values:** ``(R, G, B, A)`` or + ``(R, G, B)``, where R, G, B, and A are int values in the range of + 0 to 255 inclusive, the A (alpha) value defaults to 255 if not + provided + + :type color_value: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) + + :returns: a newly created :class:`Color` object + :rtype: Color + + .. versionchanged:: 2.0.0 + Support for tuples, lists, and :class:`Color` objects when creating + :class:`Color` objects. + .. versionchanged:: 1.9.2 Color objects export the C level array interface. + .. versionchanged:: 1.9.0 Color objects support 4-element tuples of integers. + .. versionchanged:: 1.8.1 New implementation of the class. + + .. attribute:: r + + | :sl:`Gets or sets the red value of the Color.` + | :sg:`r -> int` + + The red value of the Color. + + .. ## Color.r ## + + .. attribute:: g + + | :sl:`Gets or sets the green value of the Color.` + | :sg:`g -> int` + + The green value of the Color. + + .. ## Color.g ## + + .. attribute:: b + + | :sl:`Gets or sets the blue value of the Color.` + | :sg:`b -> int` + + The blue value of the Color. + + .. ## Color.b ## + + .. attribute:: a + + | :sl:`Gets or sets the alpha value of the Color.` + | :sg:`a -> int` + + The alpha value of the Color. + + .. ## Color.a ## + + .. attribute:: cmy + + | :sl:`Gets or sets the CMY representation of the Color.` + | :sg:`cmy -> tuple` + + The ``CMY`` representation of the Color. The ``CMY`` components are in + the ranges ``C`` = [0, 1], ``M`` = [0, 1], ``Y`` = [0, 1]. Note that this + will not return the absolutely exact ``CMY`` values for the set ``RGB`` + values in all cases. Due to the ``RGB`` mapping from 0-255 and the + ``CMY`` mapping from 0-1 rounding errors may cause the ``CMY`` values to + differ slightly from what you might expect. + + .. ## Color.cmy ## + + .. attribute:: hsva + + | :sl:`Gets or sets the HSVA representation of the Color.` + | :sg:`hsva -> tuple` + + The ``HSVA`` representation of the Color. The ``HSVA`` components are in + the ranges ``H`` = [0, 360], ``S`` = [0, 100], ``V`` = [0, 100], A = [0, + 100]. Note that this will not return the absolutely exact ``HSV`` values + for the set ``RGB`` values in all cases. Due to the ``RGB`` mapping from + 0-255 and the ``HSV`` mapping from 0-100 and 0-360 rounding errors may + cause the ``HSV`` values to differ slightly from what you might expect. + + .. ## Color.hsva ## + + .. attribute:: hsla + + | :sl:`Gets or sets the HSLA representation of the Color.` + | :sg:`hsla -> tuple` + + The ``HSLA`` representation of the Color. The ``HSLA`` components are in + the ranges ``H`` = [0, 360], ``S`` = [0, 100], ``L`` = [0, 100], A = [0, + 100]. Note that this will not return the absolutely exact ``HSL`` values + for the set ``RGB`` values in all cases. Due to the ``RGB`` mapping from + 0-255 and the ``HSL`` mapping from 0-100 and 0-360 rounding errors may + cause the ``HSL`` values to differ slightly from what you might expect. + + .. ## Color.hsla ## + + .. attribute:: i1i2i3 + + | :sl:`Gets or sets the I1I2I3 representation of the Color.` + | :sg:`i1i2i3 -> tuple` + + The ``I1I2I3`` representation of the Color. The ``I1I2I3`` components are + in the ranges ``I1`` = [0, 1], ``I2`` = [-0.5, 0.5], ``I3`` = [-0.5, + 0.5]. Note that this will not return the absolutely exact ``I1I2I3`` + values for the set ``RGB`` values in all cases. Due to the ``RGB`` + mapping from 0-255 and the ``I1I2I3`` mapping from 0-1 rounding errors + may cause the ``I1I2I3`` values to differ slightly from what you might + expect. + + .. ## Color.i1i2i3 ## + + .. method:: normalize + + | :sl:`Returns the normalized RGBA values of the Color.` + | :sg:`normalize() -> tuple` + + Returns the normalized ``RGBA`` values of the Color as floating point + values. + + .. ## Color.normalize ## + + .. method:: correct_gamma + + | :sl:`Applies a certain gamma value to the Color.` + | :sg:`correct_gamma (gamma) -> Color` + + Applies a certain gamma value to the Color and returns a new Color with + the adjusted ``RGBA`` values. + + .. ## Color.correct_gamma ## + + .. method:: set_length + + | :sl:`Set the number of elements in the Color to 1,2,3, or 4.` + | :sg:`set_length(len) -> None` + + DEPRECATED: You may unpack the values you need like so, + ``r, g, b, _ = pygame.Color(100, 100, 100)`` + If you only want r, g and b + Or + ``r, g, *_ = pygame.Color(100, 100, 100)`` + if you only want r and g + + The default Color length is 4. Colors can have lengths 1,2,3 or 4. This + is useful if you want to unpack to r,g,b and not r,g,b,a. If you want to + get the length of a Color do ``len(acolor)``. + + .. deprecated:: 2.1.3 + .. versionadded:: 1.9.0 + + .. ## Color.set_length ## + + .. method:: grayscale + + | :sl:`returns the grayscale of a Color` + | :sg:`grayscale() -> Color` + + Returns a Color which represents the grayscaled version of self using the luminosity formula which weights red, green and blue according to their wavelengths.. + + .. ## Color.grayscale ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given Color.` + | :sg:`lerp(Color, float) -> Color` + + Returns a Color which is a linear interpolation between self and the + given Color in RGBA space. The second parameter determines how far + between self and other the result is going to be. + It must be a value between 0 and 1 where 0 means self and 1 means + other will be returned. + + .. versionadded:: 2.0.1 + + .. ## Color.lerp ## + + .. method:: premul_alpha + + | :sl:`returns a Color where the r,g,b components have been multiplied by the alpha.` + | :sg:`premul_alpha() -> Color` + + Returns a new Color where each of the red, green and blue colour + channels have been multiplied by the alpha channel of the original + color. The alpha channel remains unchanged. + + This is useful when working with the ``BLEND_PREMULTIPLIED`` blending mode + flag for :meth:`pygame.Surface.blit()`, which assumes that all surfaces using + it are using pre-multiplied alpha colors. + + .. versionadded:: 2.0.0 + + .. ## Color.premul_alpha ## + + .. method:: update + + | :sl:`Sets the elements of the color` + | :sg:`update(r, g, b) -> None` + | :sg:`update(r, g, b, a=255) -> None` + | :sg:`update(color_value) -> None` + + Sets the elements of the color. See parameters for :meth:`pygame.Color` for the + parameters of this function. If the alpha value was not set it will not change. + + .. versionadded:: 2.0.1 + + .. ## Color.update ## + .. ## pygame.Color ## diff --git a/docs/ref/color_list.rst b/docs/ref/color_list.rst new file mode 100644 index 0000000..b6cf289 --- /dev/null +++ b/docs/ref/color_list.rst @@ -0,0 +1,2014 @@ +.. include:: common.txt + +Named Colors +============ + +.. raw:: html + + + +:doc:`color` lets you specify any of these named colors when creating a new +``pygame.Color`` (taken from the +`colordict module `_). + +.. role:: aliceblue +.. role:: antiquewhite +.. role:: antiquewhite1 +.. role:: antiquewhite2 +.. role:: antiquewhite3 +.. role:: antiquewhite4 +.. role:: aqua +.. role:: aquamarine +.. role:: aquamarine1 +.. role:: aquamarine2 +.. role:: aquamarine3 +.. role:: aquamarine4 +.. role:: azure +.. role:: azure1 +.. role:: azure2 +.. role:: azure3 +.. role:: azure4 +.. role:: beige +.. role:: bisque +.. role:: bisque1 +.. role:: bisque2 +.. role:: bisque3 +.. role:: bisque4 +.. role:: black +.. role:: blanchedalmond +.. role:: blue +.. role:: blue1 +.. role:: blue2 +.. role:: blue3 +.. role:: blue4 +.. role:: blueviolet +.. role:: brown +.. role:: brown1 +.. role:: brown2 +.. role:: brown3 +.. role:: brown4 +.. role:: burlywood +.. role:: burlywood1 +.. role:: burlywood2 +.. role:: burlywood3 +.. role:: burlywood4 +.. role:: cadetblue +.. role:: cadetblue1 +.. role:: cadetblue2 +.. role:: cadetblue3 +.. role:: cadetblue4 +.. role:: chartreuse +.. role:: chartreuse1 +.. role:: chartreuse2 +.. role:: chartreuse3 +.. role:: chartreuse4 +.. role:: chocolate +.. role:: chocolate1 +.. role:: chocolate2 +.. role:: chocolate3 +.. role:: chocolate4 +.. role:: coral +.. role:: coral1 +.. role:: coral2 +.. role:: coral3 +.. role:: coral4 +.. role:: cornflowerblue +.. role:: cornsilk +.. role:: cornsilk1 +.. role:: cornsilk2 +.. role:: cornsilk3 +.. role:: cornsilk4 +.. role:: crimson +.. role:: cyan +.. role:: cyan1 +.. role:: cyan2 +.. role:: cyan3 +.. role:: cyan4 +.. role:: darkblue +.. role:: darkcyan +.. role:: darkgoldenrod +.. role:: darkgoldenrod1 +.. role:: darkgoldenrod2 +.. role:: darkgoldenrod3 +.. role:: darkgoldenrod4 +.. role:: darkgray +.. role:: darkgreen +.. role:: darkgrey +.. role:: darkkhaki +.. role:: darkmagenta +.. role:: darkolivegreen +.. role:: darkolivegreen1 +.. role:: darkolivegreen2 +.. role:: darkolivegreen3 +.. role:: darkolivegreen4 +.. role:: darkorange +.. role:: darkorange1 +.. role:: darkorange2 +.. role:: darkorange3 +.. role:: darkorange4 +.. role:: darkorchid +.. role:: darkorchid1 +.. role:: darkorchid2 +.. role:: darkorchid3 +.. role:: darkorchid4 +.. role:: darkred +.. role:: darksalmon +.. role:: darkseagreen +.. role:: darkseagreen1 +.. role:: darkseagreen2 +.. role:: darkseagreen3 +.. role:: darkseagreen4 +.. role:: darkslateblue +.. role:: darkslategray +.. role:: darkslategray1 +.. role:: darkslategray2 +.. role:: darkslategray3 +.. role:: darkslategray4 +.. role:: darkslategrey +.. role:: darkturquoise +.. role:: darkviolet +.. role:: deeppink +.. role:: deeppink1 +.. role:: deeppink2 +.. role:: deeppink3 +.. role:: deeppink4 +.. role:: deepskyblue +.. role:: deepskyblue1 +.. role:: deepskyblue2 +.. role:: deepskyblue3 +.. role:: deepskyblue4 +.. role:: dimgray +.. role:: dimgrey +.. role:: dodgerblue +.. role:: dodgerblue1 +.. role:: dodgerblue2 +.. role:: dodgerblue3 +.. role:: dodgerblue4 +.. role:: firebrick +.. role:: firebrick1 +.. role:: firebrick2 +.. role:: firebrick3 +.. role:: firebrick4 +.. role:: floralwhite +.. role:: forestgreen +.. role:: fuchsia +.. role:: gainsboro +.. role:: ghostwhite +.. role:: gold +.. role:: gold1 +.. role:: gold2 +.. role:: gold3 +.. role:: gold4 +.. role:: goldenrod +.. role:: goldenrod1 +.. role:: goldenrod2 +.. role:: goldenrod3 +.. role:: goldenrod4 +.. role:: gray +.. role:: gray0 +.. role:: gray1 +.. role:: gray2 +.. role:: gray3 +.. role:: gray4 +.. role:: gray5 +.. role:: gray6 +.. role:: gray7 +.. role:: gray8 +.. role:: gray9 +.. role:: gray10 +.. role:: gray11 +.. role:: gray12 +.. role:: gray13 +.. role:: gray14 +.. role:: gray15 +.. role:: gray16 +.. role:: gray17 +.. role:: gray18 +.. role:: gray19 +.. role:: gray20 +.. role:: gray21 +.. role:: gray22 +.. role:: gray23 +.. role:: gray24 +.. role:: gray25 +.. role:: gray26 +.. role:: gray27 +.. role:: gray28 +.. role:: gray29 +.. role:: gray30 +.. role:: gray31 +.. role:: gray32 +.. role:: gray33 +.. role:: gray34 +.. role:: gray35 +.. role:: gray36 +.. role:: gray37 +.. role:: gray38 +.. role:: gray39 +.. role:: gray40 +.. role:: gray41 +.. role:: gray42 +.. role:: gray43 +.. role:: gray44 +.. role:: gray45 +.. role:: gray46 +.. role:: gray47 +.. role:: gray48 +.. role:: gray49 +.. role:: gray50 +.. role:: gray51 +.. role:: gray52 +.. role:: gray53 +.. role:: gray54 +.. role:: gray55 +.. role:: gray56 +.. role:: gray57 +.. role:: gray58 +.. role:: gray59 +.. role:: gray60 +.. role:: gray61 +.. role:: gray62 +.. role:: gray63 +.. role:: gray64 +.. role:: gray65 +.. role:: gray66 +.. role:: gray67 +.. role:: gray68 +.. role:: gray69 +.. role:: gray70 +.. role:: gray71 +.. role:: gray72 +.. role:: gray73 +.. role:: gray74 +.. role:: gray75 +.. role:: gray76 +.. role:: gray77 +.. role:: gray78 +.. role:: gray79 +.. role:: gray80 +.. role:: gray81 +.. role:: gray82 +.. role:: gray83 +.. role:: gray84 +.. role:: gray85 +.. role:: gray86 +.. role:: gray87 +.. role:: gray88 +.. role:: gray89 +.. role:: gray90 +.. role:: gray91 +.. role:: gray92 +.. role:: gray93 +.. role:: gray94 +.. role:: gray95 +.. role:: gray96 +.. role:: gray97 +.. role:: gray98 +.. role:: gray99 +.. role:: gray100 +.. role:: green +.. role:: green1 +.. role:: green2 +.. role:: green3 +.. role:: green4 +.. role:: greenyellow +.. role:: grey +.. role:: grey0 +.. role:: grey1 +.. role:: grey2 +.. role:: grey3 +.. role:: grey4 +.. role:: grey5 +.. role:: grey6 +.. role:: grey7 +.. role:: grey8 +.. role:: grey9 +.. role:: grey10 +.. role:: grey11 +.. role:: grey12 +.. role:: grey13 +.. role:: grey14 +.. role:: grey15 +.. role:: grey16 +.. role:: grey17 +.. role:: grey18 +.. role:: grey19 +.. role:: grey20 +.. role:: grey21 +.. role:: grey22 +.. role:: grey23 +.. role:: grey24 +.. role:: grey25 +.. role:: grey26 +.. role:: grey27 +.. role:: grey28 +.. role:: grey29 +.. role:: grey30 +.. role:: grey31 +.. role:: grey32 +.. role:: grey33 +.. role:: grey34 +.. role:: grey35 +.. role:: grey36 +.. role:: grey37 +.. role:: grey38 +.. role:: grey39 +.. role:: grey40 +.. role:: grey41 +.. role:: grey42 +.. role:: grey43 +.. role:: grey44 +.. role:: grey45 +.. role:: grey46 +.. role:: grey47 +.. role:: grey48 +.. role:: grey49 +.. role:: grey50 +.. role:: grey51 +.. role:: grey52 +.. role:: grey53 +.. role:: grey54 +.. role:: grey55 +.. role:: grey56 +.. role:: grey57 +.. role:: grey58 +.. role:: grey59 +.. role:: grey60 +.. role:: grey61 +.. role:: grey62 +.. role:: grey63 +.. role:: grey64 +.. role:: grey65 +.. role:: grey66 +.. role:: grey67 +.. role:: grey68 +.. role:: grey69 +.. role:: grey70 +.. role:: grey71 +.. role:: grey72 +.. role:: grey73 +.. role:: grey74 +.. role:: grey75 +.. role:: grey76 +.. role:: grey77 +.. role:: grey78 +.. role:: grey79 +.. role:: grey80 +.. role:: grey81 +.. role:: grey82 +.. role:: grey83 +.. role:: grey84 +.. role:: grey85 +.. role:: grey86 +.. role:: grey87 +.. role:: grey88 +.. role:: grey89 +.. role:: grey90 +.. role:: grey91 +.. role:: grey92 +.. role:: grey93 +.. role:: grey94 +.. role:: grey95 +.. role:: grey96 +.. role:: grey97 +.. role:: grey98 +.. role:: grey99 +.. role:: grey100 +.. role:: honeydew +.. role:: honeydew1 +.. role:: honeydew2 +.. role:: honeydew3 +.. role:: honeydew4 +.. role:: hotpink +.. role:: hotpink1 +.. role:: hotpink2 +.. role:: hotpink3 +.. role:: hotpink4 +.. role:: indianred +.. role:: indianred1 +.. role:: indianred2 +.. role:: indianred3 +.. role:: indianred4 +.. role:: indigo +.. role:: ivory +.. role:: ivory1 +.. role:: ivory2 +.. role:: ivory3 +.. role:: ivory4 +.. role:: khaki +.. role:: khaki1 +.. role:: khaki2 +.. role:: khaki3 +.. role:: khaki4 +.. role:: lavender +.. role:: lavenderblush +.. role:: lavenderblush1 +.. role:: lavenderblush2 +.. role:: lavenderblush3 +.. role:: lavenderblush4 +.. role:: lawngreen +.. role:: lemonchiffon +.. role:: lemonchiffon1 +.. role:: lemonchiffon2 +.. role:: lemonchiffon3 +.. role:: lemonchiffon4 +.. role:: lightblue +.. role:: lightblue1 +.. role:: lightblue2 +.. role:: lightblue3 +.. role:: lightblue4 +.. role:: lightcoral +.. role:: lightcyan +.. role:: lightcyan1 +.. role:: lightcyan2 +.. role:: lightcyan3 +.. role:: lightcyan4 +.. role:: lightgoldenrod +.. role:: lightgoldenrod1 +.. role:: lightgoldenrod2 +.. role:: lightgoldenrod3 +.. role:: lightgoldenrod4 +.. role:: lightgoldenrodyellow +.. role:: lightgray +.. role:: lightgreen +.. role:: lightgrey +.. role:: lightpink +.. role:: lightpink1 +.. role:: lightpink2 +.. role:: lightpink3 +.. role:: lightpink4 +.. role:: lightsalmon +.. role:: lightsalmon1 +.. role:: lightsalmon2 +.. role:: lightsalmon3 +.. role:: lightsalmon4 +.. role:: lightseagreen +.. role:: lightskyblue +.. role:: lightskyblue1 +.. role:: lightskyblue2 +.. role:: lightskyblue3 +.. role:: lightskyblue4 +.. role:: lightslateblue +.. role:: lightslategray +.. role:: lightslategrey +.. role:: lightsteelblue +.. role:: lightsteelblue1 +.. role:: lightsteelblue2 +.. role:: lightsteelblue3 +.. role:: lightsteelblue4 +.. role:: lightyellow +.. role:: lightyellow1 +.. role:: lightyellow2 +.. role:: lightyellow3 +.. role:: lightyellow4 +.. role:: limegreen +.. role:: lime +.. role:: linen +.. role:: magenta +.. role:: magenta1 +.. role:: magenta2 +.. role:: magenta3 +.. role:: magenta4 +.. role:: maroon +.. role:: maroon1 +.. role:: maroon2 +.. role:: maroon3 +.. role:: maroon4 +.. role:: mediumaquamarine +.. role:: mediumblue +.. role:: mediumorchid +.. role:: mediumorchid1 +.. role:: mediumorchid2 +.. role:: mediumorchid3 +.. role:: mediumorchid4 +.. role:: mediumpurple +.. role:: mediumpurple1 +.. role:: mediumpurple2 +.. role:: mediumpurple3 +.. role:: mediumpurple4 +.. role:: mediumseagreen +.. role:: mediumslateblue +.. role:: mediumspringgreen +.. role:: mediumturquoise +.. role:: mediumvioletred +.. role:: midnightblue +.. role:: mintcream +.. role:: mistyrose +.. role:: mistyrose1 +.. role:: mistyrose2 +.. role:: mistyrose3 +.. role:: mistyrose4 +.. role:: moccasin +.. role:: navajowhite +.. role:: navajowhite1 +.. role:: navajowhite2 +.. role:: navajowhite3 +.. role:: navajowhite4 +.. role:: navy +.. role:: navyblue +.. role:: oldlace +.. role:: olive +.. role:: olivedrab +.. role:: olivedrab1 +.. role:: olivedrab2 +.. role:: olivedrab3 +.. role:: olivedrab4 +.. role:: orange +.. role:: orange1 +.. role:: orange2 +.. role:: orange3 +.. role:: orange4 +.. role:: orangered +.. role:: orangered1 +.. role:: orangered2 +.. role:: orangered3 +.. role:: orangered4 +.. role:: orchid +.. role:: orchid1 +.. role:: orchid2 +.. role:: orchid3 +.. role:: orchid4 +.. role:: palegoldenrod +.. role:: palegreen +.. role:: palegreen1 +.. role:: palegreen2 +.. role:: palegreen3 +.. role:: palegreen4 +.. role:: paleturquoise +.. role:: paleturquoise1 +.. role:: paleturquoise2 +.. role:: paleturquoise3 +.. role:: paleturquoise4 +.. role:: palevioletred +.. role:: palevioletred1 +.. role:: palevioletred2 +.. role:: palevioletred3 +.. role:: palevioletred4 +.. role:: papayawhip +.. role:: peachpuff +.. role:: peachpuff1 +.. role:: peachpuff2 +.. role:: peachpuff3 +.. role:: peachpuff4 +.. role:: peru +.. role:: pink +.. role:: pink1 +.. role:: pink2 +.. role:: pink3 +.. role:: pink4 +.. role:: plum +.. role:: plum1 +.. role:: plum2 +.. role:: plum3 +.. role:: plum4 +.. role:: powderblue +.. role:: purple +.. role:: purple1 +.. role:: purple2 +.. role:: purple3 +.. role:: purple4 +.. role:: red +.. role:: red1 +.. role:: red2 +.. role:: red3 +.. role:: red4 +.. role:: rosybrown +.. role:: rosybrown1 +.. role:: rosybrown2 +.. role:: rosybrown3 +.. role:: rosybrown4 +.. role:: royalblue +.. role:: royalblue1 +.. role:: royalblue2 +.. role:: royalblue3 +.. role:: royalblue4 +.. role:: saddlebrown +.. role:: salmon +.. role:: salmon1 +.. role:: salmon2 +.. role:: salmon3 +.. role:: salmon4 +.. role:: sandybrown +.. role:: seagreen +.. role:: seagreen1 +.. role:: seagreen2 +.. role:: seagreen3 +.. role:: seagreen4 +.. role:: seashell +.. role:: seashell1 +.. role:: seashell2 +.. role:: seashell3 +.. role:: seashell4 +.. role:: sienna +.. role:: sienna1 +.. role:: sienna2 +.. role:: sienna3 +.. role:: sienna4 +.. role:: silver +.. role:: skyblue +.. role:: skyblue1 +.. role:: skyblue2 +.. role:: skyblue3 +.. role:: skyblue4 +.. role:: slateblue +.. role:: slateblue1 +.. role:: slateblue2 +.. role:: slateblue3 +.. role:: slateblue4 +.. role:: slategray +.. role:: slategray1 +.. role:: slategray2 +.. role:: slategray3 +.. role:: slategray4 +.. role:: slategrey +.. role:: snow +.. role:: snow1 +.. role:: snow2 +.. role:: snow3 +.. role:: snow4 +.. role:: springgreen +.. role:: springgreen1 +.. role:: springgreen2 +.. role:: springgreen3 +.. role:: springgreen4 +.. role:: steelblue +.. role:: steelblue1 +.. role:: steelblue2 +.. role:: steelblue3 +.. role:: steelblue4 +.. role:: tan +.. role:: tan1 +.. role:: tan2 +.. role:: tan3 +.. role:: tan4 +.. role:: teal +.. role:: thistle +.. role:: thistle1 +.. role:: thistle2 +.. role:: thistle3 +.. role:: thistle4 +.. role:: tomato +.. role:: tomato1 +.. role:: tomato2 +.. role:: tomato3 +.. role:: tomato4 +.. role:: turquoise +.. role:: turquoise1 +.. role:: turquoise2 +.. role:: turquoise3 +.. role:: turquoise4 +.. role:: violet +.. role:: violetred +.. role:: violetred1 +.. role:: violetred2 +.. role:: violetred3 +.. role:: violetred4 +.. role:: wheat +.. role:: wheat1 +.. role:: wheat2 +.. role:: wheat3 +.. role:: wheat4 +.. role:: white +.. role:: whitesmoke +.. role:: yellow +.. role:: yellow1 +.. role:: yellow2 +.. role:: yellow3 +.. role:: yellow4 +.. role:: yellowgreen + +========================== ====================================================================================================== +Name Color +========================== ====================================================================================================== +``aliceblue`` :aliceblue:`████████` +``antiquewhite`` :antiquewhite:`████████` +``antiquewhite1`` :antiquewhite1:`████████` +``antiquewhite2`` :antiquewhite2:`████████` +``antiquewhite3`` :antiquewhite3:`████████` +``antiquewhite4`` :antiquewhite4:`████████` +``aqua`` :aqua:`████████` +``aquamarine`` :aquamarine:`████████` +``aquamarine1`` :aquamarine1:`████████` +``aquamarine2`` :aquamarine2:`████████` +``aquamarine3`` :aquamarine3:`████████` +``aquamarine4`` :aquamarine4:`████████` +``azure`` :azure:`████████` +``azure1`` :azure1:`████████` +``azure2`` :azure2:`████████` +``azure3`` :azure3:`████████` +``azure4`` :azure4:`████████` +``beige`` :beige:`████████` +``bisque`` :bisque:`████████` +``bisque1`` :bisque1:`████████` +``bisque2`` :bisque2:`████████` +``bisque3`` :bisque3:`████████` +``bisque4`` :bisque4:`████████` +``black`` :black:`████████` +``blanchedalmond`` :blanchedalmond:`████████` +``blue`` :blue:`████████` +``blue1`` :blue1:`████████` +``blue2`` :blue2:`████████` +``blue3`` :blue3:`████████` +``blue4`` :blue4:`████████` +``blueviolet`` :blueviolet:`████████` +``brown`` :brown:`████████` +``brown1`` :brown1:`████████` +``brown2`` :brown2:`████████` +``brown3`` :brown3:`████████` +``brown4`` :brown4:`████████` +``burlywood`` :burlywood:`████████` +``burlywood1`` :burlywood1:`████████` +``burlywood2`` :burlywood2:`████████` +``burlywood3`` :burlywood3:`████████` +``burlywood4`` :burlywood4:`████████` +``cadetblue`` :cadetblue:`████████` +``cadetblue1`` :cadetblue1:`████████` +``cadetblue2`` :cadetblue2:`████████` +``cadetblue3`` :cadetblue3:`████████` +``cadetblue4`` :cadetblue4:`████████` +``chartreuse`` :chartreuse:`████████` +``chartreuse1`` :chartreuse1:`████████` +``chartreuse2`` :chartreuse2:`████████` +``chartreuse3`` :chartreuse3:`████████` +``chartreuse4`` :chartreuse4:`████████` +``chocolate`` :chocolate:`████████` +``chocolate1`` :chocolate1:`████████` +``chocolate2`` :chocolate2:`████████` +``chocolate3`` :chocolate3:`████████` +``chocolate4`` :chocolate4:`████████` +``coral`` :coral:`████████` +``coral1`` :coral1:`████████` +``coral2`` :coral2:`████████` +``coral3`` :coral3:`████████` +``coral4`` :coral4:`████████` +``cornflowerblue`` :cornflowerblue:`████████` +``cornsilk`` :cornsilk:`████████` +``cornsilk1`` :cornsilk1:`████████` +``cornsilk2`` :cornsilk2:`████████` +``cornsilk3`` :cornsilk3:`████████` +``cornsilk4`` :cornsilk4:`████████` +``crimson`` :crimson:`████████` +``cyan`` :cyan:`████████` +``cyan1`` :cyan1:`████████` +``cyan2`` :cyan2:`████████` +``cyan3`` :cyan3:`████████` +``cyan4`` :cyan4:`████████` +``darkblue`` :darkblue:`████████` +``darkcyan`` :darkcyan:`████████` +``darkgoldenrod`` :darkgoldenrod:`████████` +``darkgoldenrod1`` :darkgoldenrod1:`████████` +``darkgoldenrod2`` :darkgoldenrod2:`████████` +``darkgoldenrod3`` :darkgoldenrod3:`████████` +``darkgoldenrod4`` :darkgoldenrod4:`████████` +``darkgray`` :darkgray:`████████` +``darkgreen`` :darkgreen:`████████` +``darkgrey`` :darkgrey:`████████` +``darkkhaki`` :darkkhaki:`████████` +``darkmagenta`` :darkmagenta:`████████` +``darkolivegreen`` :darkolivegreen:`████████` +``darkolivegreen1`` :darkolivegreen1:`████████` +``darkolivegreen2`` :darkolivegreen2:`████████` +``darkolivegreen3`` :darkolivegreen3:`████████` +``darkolivegreen4`` :darkolivegreen4:`████████` +``darkorange`` :darkorange:`████████` +``darkorange1`` :darkorange1:`████████` +``darkorange2`` :darkorange2:`████████` +``darkorange3`` :darkorange3:`████████` +``darkorange4`` :darkorange4:`████████` +``darkorchid`` :darkorchid:`████████` +``darkorchid1`` :darkorchid1:`████████` +``darkorchid2`` :darkorchid2:`████████` +``darkorchid3`` :darkorchid3:`████████` +``darkorchid4`` :darkorchid4:`████████` +``darkred`` :darkred:`████████` +``darksalmon`` :darksalmon:`████████` +``darkseagreen`` :darkseagreen:`████████` +``darkseagreen1`` :darkseagreen1:`████████` +``darkseagreen2`` :darkseagreen2:`████████` +``darkseagreen3`` :darkseagreen3:`████████` +``darkseagreen4`` :darkseagreen4:`████████` +``darkslateblue`` :darkslateblue:`████████` +``darkslategray`` :darkslategray:`████████` +``darkslategray1`` :darkslategray1:`████████` +``darkslategray2`` :darkslategray2:`████████` +``darkslategray3`` :darkslategray3:`████████` +``darkslategray4`` :darkslategray4:`████████` +``darkslategrey`` :darkslategrey:`████████` +``darkturquoise`` :darkturquoise:`████████` +``darkviolet`` :darkviolet:`████████` +``deeppink`` :deeppink:`████████` +``deeppink1`` :deeppink1:`████████` +``deeppink2`` :deeppink2:`████████` +``deeppink3`` :deeppink3:`████████` +``deeppink4`` :deeppink4:`████████` +``deepskyblue`` :deepskyblue:`████████` +``deepskyblue1`` :deepskyblue1:`████████` +``deepskyblue2`` :deepskyblue2:`████████` +``deepskyblue3`` :deepskyblue3:`████████` +``deepskyblue4`` :deepskyblue4:`████████` +``dimgray`` :dimgray:`████████` +``dimgrey`` :dimgrey:`████████` +``dodgerblue`` :dodgerblue:`████████` +``dodgerblue1`` :dodgerblue1:`████████` +``dodgerblue2`` :dodgerblue2:`████████` +``dodgerblue3`` :dodgerblue3:`████████` +``dodgerblue4`` :dodgerblue4:`████████` +``firebrick`` :firebrick:`████████` +``firebrick1`` :firebrick1:`████████` +``firebrick2`` :firebrick2:`████████` +``firebrick3`` :firebrick3:`████████` +``firebrick4`` :firebrick4:`████████` +``floralwhite`` :floralwhite:`████████` +``forestgreen`` :forestgreen:`████████` +``fuchsia`` :fuchsia:`████████` +``gainsboro`` :gainsboro:`████████` +``ghostwhite`` :ghostwhite:`████████` +``gold`` :gold:`████████` +``gold1`` :gold1:`████████` +``gold2`` :gold2:`████████` +``gold3`` :gold3:`████████` +``gold4`` :gold4:`████████` +``goldenrod`` :goldenrod:`████████` +``goldenrod1`` :goldenrod1:`████████` +``goldenrod2`` :goldenrod2:`████████` +``goldenrod3`` :goldenrod3:`████████` +``goldenrod4`` :goldenrod4:`████████` +``gray`` :gray:`████████` +``gray0`` :gray0:`████████` +``gray1`` :gray1:`████████` +``gray2`` :gray2:`████████` +``gray3`` :gray3:`████████` +``gray4`` :gray4:`████████` +``gray5`` :gray5:`████████` +``gray6`` :gray6:`████████` +``gray7`` :gray7:`████████` +``gray8`` :gray8:`████████` +``gray9`` :gray9:`████████` +``gray10`` :gray10:`████████` +``gray11`` :gray11:`████████` +``gray12`` :gray12:`████████` +``gray13`` :gray13:`████████` +``gray14`` :gray14:`████████` +``gray15`` :gray15:`████████` +``gray16`` :gray16:`████████` +``gray17`` :gray17:`████████` +``gray18`` :gray18:`████████` +``gray19`` :gray19:`████████` +``gray20`` :gray20:`████████` +``gray21`` :gray21:`████████` +``gray22`` :gray22:`████████` +``gray23`` :gray23:`████████` +``gray24`` :gray24:`████████` +``gray25`` :gray25:`████████` +``gray26`` :gray26:`████████` +``gray27`` :gray27:`████████` +``gray28`` :gray28:`████████` +``gray29`` :gray29:`████████` +``gray30`` :gray30:`████████` +``gray31`` :gray31:`████████` +``gray32`` :gray32:`████████` +``gray33`` :gray33:`████████` +``gray34`` :gray34:`████████` +``gray35`` :gray35:`████████` +``gray36`` :gray36:`████████` +``gray37`` :gray37:`████████` +``gray38`` :gray38:`████████` +``gray39`` :gray39:`████████` +``gray40`` :gray40:`████████` +``gray41`` :gray41:`████████` +``gray42`` :gray42:`████████` +``gray43`` :gray43:`████████` +``gray44`` :gray44:`████████` +``gray45`` :gray45:`████████` +``gray46`` :gray46:`████████` +``gray47`` :gray47:`████████` +``gray48`` :gray48:`████████` +``gray49`` :gray49:`████████` +``gray50`` :gray50:`████████` +``gray51`` :gray51:`████████` +``gray52`` :gray52:`████████` +``gray53`` :gray53:`████████` +``gray54`` :gray54:`████████` +``gray55`` :gray55:`████████` +``gray56`` :gray56:`████████` +``gray57`` :gray57:`████████` +``gray58`` :gray58:`████████` +``gray59`` :gray59:`████████` +``gray60`` :gray60:`████████` +``gray61`` :gray61:`████████` +``gray62`` :gray62:`████████` +``gray63`` :gray63:`████████` +``gray64`` :gray64:`████████` +``gray65`` :gray65:`████████` +``gray66`` :gray66:`████████` +``gray67`` :gray67:`████████` +``gray68`` :gray68:`████████` +``gray69`` :gray69:`████████` +``gray70`` :gray70:`████████` +``gray71`` :gray71:`████████` +``gray72`` :gray72:`████████` +``gray73`` :gray73:`████████` +``gray74`` :gray74:`████████` +``gray75`` :gray75:`████████` +``gray76`` :gray76:`████████` +``gray77`` :gray77:`████████` +``gray78`` :gray78:`████████` +``gray79`` :gray79:`████████` +``gray80`` :gray80:`████████` +``gray81`` :gray81:`████████` +``gray82`` :gray82:`████████` +``gray83`` :gray83:`████████` +``gray84`` :gray84:`████████` +``gray85`` :gray85:`████████` +``gray86`` :gray86:`████████` +``gray87`` :gray87:`████████` +``gray88`` :gray88:`████████` +``gray89`` :gray89:`████████` +``gray90`` :gray90:`████████` +``gray91`` :gray91:`████████` +``gray92`` :gray92:`████████` +``gray93`` :gray93:`████████` +``gray94`` :gray94:`████████` +``gray95`` :gray95:`████████` +``gray96`` :gray96:`████████` +``gray97`` :gray97:`████████` +``gray98`` :gray98:`████████` +``gray99`` :gray99:`████████` +``gray100`` :gray100:`████████` +``green`` :green:`████████` +``green1`` :green1:`████████` +``green2`` :green2:`████████` +``green3`` :green3:`████████` +``green4`` :green4:`████████` +``greenyellow`` :greenyellow:`████████` +``grey`` :grey:`████████` +``grey0`` :grey0:`████████` +``grey1`` :grey1:`████████` +``grey2`` :grey2:`████████` +``grey3`` :grey3:`████████` +``grey4`` :grey4:`████████` +``grey5`` :grey5:`████████` +``grey6`` :grey6:`████████` +``grey7`` :grey7:`████████` +``grey8`` :grey8:`████████` +``grey9`` :grey9:`████████` +``grey10`` :grey10:`████████` +``grey11`` :grey11:`████████` +``grey12`` :grey12:`████████` +``grey13`` :grey13:`████████` +``grey14`` :grey14:`████████` +``grey15`` :grey15:`████████` +``grey16`` :grey16:`████████` +``grey17`` :grey17:`████████` +``grey18`` :grey18:`████████` +``grey19`` :grey19:`████████` +``grey20`` :grey20:`████████` +``grey21`` :grey21:`████████` +``grey22`` :grey22:`████████` +``grey23`` :grey23:`████████` +``grey24`` :grey24:`████████` +``grey25`` :grey25:`████████` +``grey26`` :grey26:`████████` +``grey27`` :grey27:`████████` +``grey28`` :grey28:`████████` +``grey29`` :grey29:`████████` +``grey30`` :grey30:`████████` +``grey31`` :grey31:`████████` +``grey32`` :grey32:`████████` +``grey33`` :grey33:`████████` +``grey34`` :grey34:`████████` +``grey35`` :grey35:`████████` +``grey36`` :grey36:`████████` +``grey37`` :grey37:`████████` +``grey38`` :grey38:`████████` +``grey39`` :grey39:`████████` +``grey40`` :grey40:`████████` +``grey41`` :grey41:`████████` +``grey42`` :grey42:`████████` +``grey43`` :grey43:`████████` +``grey44`` :grey44:`████████` +``grey45`` :grey45:`████████` +``grey46`` :grey46:`████████` +``grey47`` :grey47:`████████` +``grey48`` :grey48:`████████` +``grey49`` :grey49:`████████` +``grey50`` :grey50:`████████` +``grey51`` :grey51:`████████` +``grey52`` :grey52:`████████` +``grey53`` :grey53:`████████` +``grey54`` :grey54:`████████` +``grey55`` :grey55:`████████` +``grey56`` :grey56:`████████` +``grey57`` :grey57:`████████` +``grey58`` :grey58:`████████` +``grey59`` :grey59:`████████` +``grey60`` :grey60:`████████` +``grey61`` :grey61:`████████` +``grey62`` :grey62:`████████` +``grey63`` :grey63:`████████` +``grey64`` :grey64:`████████` +``grey65`` :grey65:`████████` +``grey66`` :grey66:`████████` +``grey67`` :grey67:`████████` +``grey68`` :grey68:`████████` +``grey69`` :grey69:`████████` +``grey70`` :grey70:`████████` +``grey71`` :grey71:`████████` +``grey72`` :grey72:`████████` +``grey73`` :grey73:`████████` +``grey74`` :grey74:`████████` +``grey75`` :grey75:`████████` +``grey76`` :grey76:`████████` +``grey77`` :grey77:`████████` +``grey78`` :grey78:`████████` +``grey79`` :grey79:`████████` +``grey80`` :grey80:`████████` +``grey81`` :grey81:`████████` +``grey82`` :grey82:`████████` +``grey83`` :grey83:`████████` +``grey84`` :grey84:`████████` +``grey85`` :grey85:`████████` +``grey86`` :grey86:`████████` +``grey87`` :grey87:`████████` +``grey88`` :grey88:`████████` +``grey89`` :grey89:`████████` +``grey90`` :grey90:`████████` +``grey91`` :grey91:`████████` +``grey92`` :grey92:`████████` +``grey93`` :grey93:`████████` +``grey94`` :grey94:`████████` +``grey95`` :grey95:`████████` +``grey96`` :grey96:`████████` +``grey97`` :grey97:`████████` +``grey98`` :grey98:`████████` +``grey99`` :grey99:`████████` +``grey100`` :grey100:`████████` +``honeydew`` :honeydew:`████████` +``honeydew1`` :honeydew1:`████████` +``honeydew2`` :honeydew2:`████████` +``honeydew3`` :honeydew3:`████████` +``honeydew4`` :honeydew4:`████████` +``hotpink`` :hotpink:`████████` +``hotpink1`` :hotpink1:`████████` +``hotpink2`` :hotpink2:`████████` +``hotpink3`` :hotpink3:`████████` +``hotpink4`` :hotpink4:`████████` +``indianred`` :indianred:`████████` +``indianred1`` :indianred1:`████████` +``indianred2`` :indianred2:`████████` +``indianred3`` :indianred3:`████████` +``indianred4`` :indianred4:`████████` +``indigo`` :indigo:`████████` +``ivory`` :ivory:`████████` +``ivory1`` :ivory1:`████████` +``ivory2`` :ivory2:`████████` +``ivory3`` :ivory3:`████████` +``ivory4`` :ivory4:`████████` +``khaki`` :khaki:`████████` +``khaki1`` :khaki1:`████████` +``khaki2`` :khaki2:`████████` +``khaki3`` :khaki3:`████████` +``khaki4`` :khaki4:`████████` +``lavender`` :lavender:`████████` +``lavenderblush`` :lavenderblush:`████████` +``lavenderblush1`` :lavenderblush1:`████████` +``lavenderblush2`` :lavenderblush2:`████████` +``lavenderblush3`` :lavenderblush3:`████████` +``lavenderblush4`` :lavenderblush4:`████████` +``lawngreen`` :lawngreen:`████████` +``lemonchiffon`` :lemonchiffon:`████████` +``lemonchiffon1`` :lemonchiffon1:`████████` +``lemonchiffon2`` :lemonchiffon2:`████████` +``lemonchiffon3`` :lemonchiffon3:`████████` +``lemonchiffon4`` :lemonchiffon4:`████████` +``lightblue`` :lightblue:`████████` +``lightblue1`` :lightblue1:`████████` +``lightblue2`` :lightblue2:`████████` +``lightblue3`` :lightblue3:`████████` +``lightblue4`` :lightblue4:`████████` +``lightcoral`` :lightcoral:`████████` +``lightcyan`` :lightcyan:`████████` +``lightcyan1`` :lightcyan1:`████████` +``lightcyan2`` :lightcyan2:`████████` +``lightcyan3`` :lightcyan3:`████████` +``lightcyan4`` :lightcyan4:`████████` +``lightgoldenrod`` :lightgoldenrod:`████████` +``lightgoldenrod1`` :lightgoldenrod1:`████████` +``lightgoldenrod2`` :lightgoldenrod2:`████████` +``lightgoldenrod3`` :lightgoldenrod3:`████████` +``lightgoldenrod4`` :lightgoldenrod4:`████████` +``lightgoldenrodyellow`` :lightgoldenrodyellow:`████████` +``lightgray`` :lightgray:`████████` +``lightgreen`` :lightgreen:`████████` +``lightgrey`` :lightgrey:`████████` +``lightpink`` :lightpink:`████████` +``lightpink1`` :lightpink1:`████████` +``lightpink2`` :lightpink2:`████████` +``lightpink3`` :lightpink3:`████████` +``lightpink4`` :lightpink4:`████████` +``lightsalmon`` :lightsalmon:`████████` +``lightsalmon1`` :lightsalmon1:`████████` +``lightsalmon2`` :lightsalmon2:`████████` +``lightsalmon3`` :lightsalmon3:`████████` +``lightsalmon4`` :lightsalmon4:`████████` +``lightseagreen`` :lightseagreen:`████████` +``lightskyblue`` :lightskyblue:`████████` +``lightskyblue1`` :lightskyblue1:`████████` +``lightskyblue2`` :lightskyblue2:`████████` +``lightskyblue3`` :lightskyblue3:`████████` +``lightskyblue4`` :lightskyblue4:`████████` +``lightslateblue`` :lightslateblue:`████████` +``lightslategray`` :lightslategray:`████████` +``lightslategrey`` :lightslategrey:`████████` +``lightsteelblue`` :lightsteelblue:`████████` +``lightsteelblue1`` :lightsteelblue1:`████████` +``lightsteelblue2`` :lightsteelblue2:`████████` +``lightsteelblue3`` :lightsteelblue3:`████████` +``lightsteelblue4`` :lightsteelblue4:`████████` +``lightyellow`` :lightyellow:`████████` +``lightyellow1`` :lightyellow1:`████████` +``lightyellow2`` :lightyellow2:`████████` +``lightyellow3`` :lightyellow3:`████████` +``lightyellow4`` :lightyellow4:`████████` +``lime`` :lime:`████████` +``limegreen`` :limegreen:`████████` +``linen`` :linen:`████████` +``magenta`` :magenta:`████████` +``magenta1`` :magenta1:`████████` +``magenta2`` :magenta2:`████████` +``magenta3`` :magenta3:`████████` +``magenta4`` :magenta4:`████████` +``maroon`` :maroon:`████████` +``maroon1`` :maroon1:`████████` +``maroon2`` :maroon2:`████████` +``maroon3`` :maroon3:`████████` +``maroon4`` :maroon4:`████████` +``mediumaquamarine`` :mediumaquamarine:`████████` +``mediumblue`` :mediumblue:`████████` +``mediumorchid`` :mediumorchid:`████████` +``mediumorchid1`` :mediumorchid1:`████████` +``mediumorchid2`` :mediumorchid2:`████████` +``mediumorchid3`` :mediumorchid3:`████████` +``mediumorchid4`` :mediumorchid4:`████████` +``mediumpurple`` :mediumpurple:`████████` +``mediumpurple1`` :mediumpurple1:`████████` +``mediumpurple2`` :mediumpurple2:`████████` +``mediumpurple3`` :mediumpurple3:`████████` +``mediumpurple4`` :mediumpurple4:`████████` +``mediumseagreen`` :mediumseagreen:`████████` +``mediumslateblue`` :mediumslateblue:`████████` +``mediumspringgreen`` :mediumspringgreen:`████████` +``mediumturquoise`` :mediumturquoise:`████████` +``mediumvioletred`` :mediumvioletred:`████████` +``midnightblue`` :midnightblue:`████████` +``mintcream`` :mintcream:`████████` +``mistyrose`` :mistyrose:`████████` +``mistyrose1`` :mistyrose1:`████████` +``mistyrose2`` :mistyrose2:`████████` +``mistyrose3`` :mistyrose3:`████████` +``mistyrose4`` :mistyrose4:`████████` +``moccasin`` :moccasin:`████████` +``navajowhite`` :navajowhite:`████████` +``navajowhite1`` :navajowhite1:`████████` +``navajowhite2`` :navajowhite2:`████████` +``navajowhite3`` :navajowhite3:`████████` +``navajowhite4`` :navajowhite4:`████████` +``navy`` :navy:`████████` +``navyblue`` :navyblue:`████████` +``oldlace`` :oldlace:`████████` +``olive`` :olive:`████████` +``olivedrab`` :olivedrab:`████████` +``olivedrab1`` :olivedrab1:`████████` +``olivedrab2`` :olivedrab2:`████████` +``olivedrab3`` :olivedrab3:`████████` +``olivedrab4`` :olivedrab4:`████████` +``orange`` :orange:`████████` +``orange1`` :orange1:`████████` +``orange2`` :orange2:`████████` +``orange3`` :orange3:`████████` +``orange4`` :orange4:`████████` +``orangered`` :orangered:`████████` +``orangered1`` :orangered1:`████████` +``orangered2`` :orangered2:`████████` +``orangered3`` :orangered3:`████████` +``orangered4`` :orangered4:`████████` +``orchid`` :orchid:`████████` +``orchid1`` :orchid1:`████████` +``orchid2`` :orchid2:`████████` +``orchid3`` :orchid3:`████████` +``orchid4`` :orchid4:`████████` +``palegoldenrod`` :palegoldenrod:`████████` +``palegreen`` :palegreen:`████████` +``palegreen1`` :palegreen1:`████████` +``palegreen2`` :palegreen2:`████████` +``palegreen3`` :palegreen3:`████████` +``palegreen4`` :palegreen4:`████████` +``paleturquoise`` :paleturquoise:`████████` +``paleturquoise1`` :paleturquoise1:`████████` +``paleturquoise2`` :paleturquoise2:`████████` +``paleturquoise3`` :paleturquoise3:`████████` +``paleturquoise4`` :paleturquoise4:`████████` +``palevioletred`` :palevioletred:`████████` +``palevioletred1`` :palevioletred1:`████████` +``palevioletred2`` :palevioletred2:`████████` +``palevioletred3`` :palevioletred3:`████████` +``palevioletred4`` :palevioletred4:`████████` +``papayawhip`` :papayawhip:`████████` +``peachpuff`` :peachpuff:`████████` +``peachpuff1`` :peachpuff1:`████████` +``peachpuff2`` :peachpuff2:`████████` +``peachpuff3`` :peachpuff3:`████████` +``peachpuff4`` :peachpuff4:`████████` +``peru`` :peru:`████████` +``pink`` :pink:`████████` +``pink1`` :pink1:`████████` +``pink2`` :pink2:`████████` +``pink3`` :pink3:`████████` +``pink4`` :pink4:`████████` +``plum`` :plum:`████████` +``plum1`` :plum1:`████████` +``plum2`` :plum2:`████████` +``plum3`` :plum3:`████████` +``plum4`` :plum4:`████████` +``powderblue`` :powderblue:`████████` +``purple`` :purple:`████████` +``purple1`` :purple1:`████████` +``purple2`` :purple2:`████████` +``purple3`` :purple3:`████████` +``purple4`` :purple4:`████████` +``red`` :red:`████████` +``red1`` :red1:`████████` +``red2`` :red2:`████████` +``red3`` :red3:`████████` +``red4`` :red4:`████████` +``rosybrown`` :rosybrown:`████████` +``rosybrown1`` :rosybrown1:`████████` +``rosybrown2`` :rosybrown2:`████████` +``rosybrown3`` :rosybrown3:`████████` +``rosybrown4`` :rosybrown4:`████████` +``royalblue`` :royalblue:`████████` +``royalblue1`` :royalblue1:`████████` +``royalblue2`` :royalblue2:`████████` +``royalblue3`` :royalblue3:`████████` +``royalblue4`` :royalblue4:`████████` +``saddlebrown`` :saddlebrown:`████████` +``salmon`` :salmon:`████████` +``salmon1`` :salmon1:`████████` +``salmon2`` :salmon2:`████████` +``salmon3`` :salmon3:`████████` +``salmon4`` :salmon4:`████████` +``sandybrown`` :sandybrown:`████████` +``seagreen`` :seagreen:`████████` +``seagreen1`` :seagreen1:`████████` +``seagreen2`` :seagreen2:`████████` +``seagreen3`` :seagreen3:`████████` +``seagreen4`` :seagreen4:`████████` +``seashell`` :seashell:`████████` +``seashell1`` :seashell1:`████████` +``seashell2`` :seashell2:`████████` +``seashell3`` :seashell3:`████████` +``seashell4`` :seashell4:`████████` +``sienna`` :sienna:`████████` +``sienna1`` :sienna1:`████████` +``sienna2`` :sienna2:`████████` +``sienna3`` :sienna3:`████████` +``sienna4`` :sienna4:`████████` +``silver`` :silver:`████████` +``skyblue`` :skyblue:`████████` +``skyblue1`` :skyblue1:`████████` +``skyblue2`` :skyblue2:`████████` +``skyblue3`` :skyblue3:`████████` +``skyblue4`` :skyblue4:`████████` +``slateblue`` :slateblue:`████████` +``slateblue1`` :slateblue1:`████████` +``slateblue2`` :slateblue2:`████████` +``slateblue3`` :slateblue3:`████████` +``slateblue4`` :slateblue4:`████████` +``slategray`` :slategray:`████████` +``slategray1`` :slategray1:`████████` +``slategray2`` :slategray2:`████████` +``slategray3`` :slategray3:`████████` +``slategray4`` :slategray4:`████████` +``slategrey`` :slategrey:`████████` +``snow`` :snow:`████████` +``snow1`` :snow1:`████████` +``snow2`` :snow2:`████████` +``snow3`` :snow3:`████████` +``snow4`` :snow4:`████████` +``springgreen`` :springgreen:`████████` +``springgreen1`` :springgreen1:`████████` +``springgreen2`` :springgreen2:`████████` +``springgreen3`` :springgreen3:`████████` +``springgreen4`` :springgreen4:`████████` +``steelblue`` :steelblue:`████████` +``steelblue1`` :steelblue1:`████████` +``steelblue2`` :steelblue2:`████████` +``steelblue3`` :steelblue3:`████████` +``steelblue4`` :steelblue4:`████████` +``tan`` :tan:`████████` +``tan1`` :tan1:`████████` +``tan2`` :tan2:`████████` +``tan3`` :tan3:`████████` +``tan4`` :tan4:`████████` +``teal`` :teal:`████████` +``thistle`` :thistle:`████████` +``thistle1`` :thistle1:`████████` +``thistle2`` :thistle2:`████████` +``thistle3`` :thistle3:`████████` +``thistle4`` :thistle4:`████████` +``tomato`` :tomato:`████████` +``tomato1`` :tomato1:`████████` +``tomato2`` :tomato2:`████████` +``tomato3`` :tomato3:`████████` +``tomato4`` :tomato4:`████████` +``turquoise`` :turquoise:`████████` +``turquoise1`` :turquoise1:`████████` +``turquoise2`` :turquoise2:`████████` +``turquoise3`` :turquoise3:`████████` +``turquoise4`` :turquoise4:`████████` +``violet`` :violet:`████████` +``violetred`` :violetred:`████████` +``violetred1`` :violetred1:`████████` +``violetred2`` :violetred2:`████████` +``violetred3`` :violetred3:`████████` +``violetred4`` :violetred4:`████████` +``wheat`` :wheat:`████████` +``wheat1`` :wheat1:`████████` +``wheat2`` :wheat2:`████████` +``wheat3`` :wheat3:`████████` +``wheat4`` :wheat4:`████████` +``white`` :white:`████████` +``whitesmoke`` :whitesmoke:`████████` +``yellow`` :yellow:`████████` +``yellow1`` :yellow1:`████████` +``yellow2`` :yellow2:`████████` +``yellow3`` :yellow3:`████████` +``yellow4`` :yellow4:`████████` +``yellowgreen`` :yellowgreen:`████████` +========================== ====================================================================================================== diff --git a/docs/ref/common.txt b/docs/ref/common.txt new file mode 100644 index 0000000..05685a1 --- /dev/null +++ b/docs/ref/common.txt @@ -0,0 +1,2 @@ +.. include:: ../common.txt + diff --git a/docs/ref/cursors.rst b/docs/ref/cursors.rst new file mode 100644 index 0000000..6ea68e2 --- /dev/null +++ b/docs/ref/cursors.rst @@ -0,0 +1,251 @@ +.. include:: common.txt + +:mod:`pygame.cursors` +===================== + +.. module:: pygame.cursors + :synopsis: pygame module for cursor resources + +| :sl:`pygame module for cursor resources` + +Pygame offers control over the system hardware cursor. Pygame supports +black and white cursors (bitmap cursors), as well as system variant cursors and color cursors. +You control the cursor with functions inside :mod:`pygame.mouse`. + +This cursors module contains functions for loading and decoding various +cursor formats. These allow you to easily store your cursors in external files +or directly as encoded python strings. + +The module includes several standard cursors. The :func:`pygame.mouse.set_cursor()` +function takes several arguments. All those arguments have been stored in a +single tuple you can call like this: + +:: + + >>> pygame.mouse.set_cursor(*pygame.cursors.arrow) + +The following variables can be passed to ``pygame.mouse.set_cursor`` function: + + * ``pygame.cursors.arrow`` + + * ``pygame.cursors.diamond`` + + * ``pygame.cursors.broken_x`` + + * ``pygame.cursors.tri_left`` + + * ``pygame.cursors.tri_right`` + +This module also contains a few cursors as formatted strings. You'll need to +pass these to ``pygame.cursors.compile()`` function before you can use them. +The example call would look like this: + +:: + + >>> cursor = pygame.cursors.compile(pygame.cursors.textmarker_strings) + >>> pygame.mouse.set_cursor((8, 16), (0, 0), *cursor) + +The following strings can be converted into cursor bitmaps with +``pygame.cursors.compile()`` : + + * ``pygame.cursors.thickarrow_strings`` + + * ``pygame.cursors.sizer_x_strings`` + + * ``pygame.cursors.sizer_y_strings`` + + * ``pygame.cursors.sizer_xy_strings`` + + * ``pygame.cursor.textmarker_strings`` + +.. function:: compile + + | :sl:`create binary cursor data from simple strings` + | :sg:`compile(strings, black='X', white='.', xor='o') -> data, mask` + + A sequence of strings can be used to create binary cursor data for the + system cursor. This returns the binary data in the form of two tuples. + Those can be passed as the third and fourth arguments respectively of the + :func:`pygame.mouse.set_cursor()` function. + + If you are creating your own cursor strings, you can use any value represent + the black and white pixels. Some system allow you to set a special toggle + color for the system color, this is also called the xor color. If the system + does not support xor cursors, that color will simply be black. + + The height must be divisible by 8. The width of the strings must all be equal + and be divisible by 8. If these two conditions are not met, ``ValueError`` is + raised. + An example set of cursor strings looks like this + + :: + + thickarrow_strings = ( #sized 24x24 + "XX ", + "XXX ", + "XXXX ", + "XX.XX ", + "XX..XX ", + "XX...XX ", + "XX....XX ", + "XX.....XX ", + "XX......XX ", + "XX.......XX ", + "XX........XX ", + "XX........XXX ", + "XX......XXXXX ", + "XX.XXX..XX ", + "XXXX XX..XX ", + "XX XX..XX ", + " XX..XX ", + " XX..XX ", + " XX..XX ", + " XXXX ", + " XX ", + " ", + " ", + " ") + + .. ## pygame.cursors.compile ## + +.. function:: load_xbm + + | :sl:`load cursor data from an XBM file` + | :sg:`load_xbm(cursorfile) -> cursor_args` + | :sg:`load_xbm(cursorfile, maskfile) -> cursor_args` + + This loads cursors for a simple subset of ``XBM`` files. ``XBM`` files are + traditionally used to store cursors on UNIX systems, they are an ASCII + format used to represent simple images. + + Sometimes the black and white color values will be split into two separate + ``XBM`` files. You can pass a second maskfile argument to load the two + images into a single cursor. + + The cursorfile and maskfile arguments can either be filenames or file-like + object with the readlines method. + + The return value cursor_args can be passed directly to the + ``pygame.mouse.set_cursor()`` function. + + .. ## pygame.cursors.load_xbm ## + + + +.. class:: Cursor + + | :sl:`pygame object representing a cursor` + | :sg:`Cursor(size, hotspot, xormasks, andmasks) -> Cursor` + | :sg:`Cursor(hotspot, surface) -> Cursor` + | :sg:`Cursor(constant) -> Cursor` + | :sg:`Cursor(Cursor) -> Cursor` + | :sg:`Cursor() -> Cursor` + + In pygame 2, there are 3 types of cursors you can create to give your + game that little bit of extra polish. There's **bitmap** type cursors, + which existed in pygame 1.x, and are compiled from a string or load from an xbm file. + Then there are **system** type cursors, where you choose a preset that will + convey the same meaning but look native across different operating systems. + Finally you can create a **color** cursor, which displays a pygame surface as the cursor. + + **Creating a system cursor** + + Choose a constant from this list, pass it into ``pygame.cursors.Cursor(constant)``, + and you're good to go. Be advised that not all systems support every system + cursor, and you may get a substitution instead. For example, on MacOS, + WAIT/WAITARROW should show up as an arrow, and SIZENWSE/SIZENESW/SIZEALL + should show up as a closed hand. And on Wayland, every SIZE cursor should + show up as a hand. + + :: + + Pygame Cursor Constant Description + -------------------------------------------- + pygame.SYSTEM_CURSOR_ARROW arrow + pygame.SYSTEM_CURSOR_IBEAM i-beam + pygame.SYSTEM_CURSOR_WAIT wait + pygame.SYSTEM_CURSOR_CROSSHAIR crosshair + pygame.SYSTEM_CURSOR_WAITARROW small wait cursor + (or wait if not available) + pygame.SYSTEM_CURSOR_SIZENWSE double arrow pointing + northwest and southeast + pygame.SYSTEM_CURSOR_SIZENESW double arrow pointing + northeast and southwest + pygame.SYSTEM_CURSOR_SIZEWE double arrow pointing + west and east + pygame.SYSTEM_CURSOR_SIZENS double arrow pointing + north and south + pygame.SYSTEM_CURSOR_SIZEALL four pointed arrow pointing + north, south, east, and west + pygame.SYSTEM_CURSOR_NO slashed circle or crossbones + pygame.SYSTEM_CURSOR_HAND hand + + **Creating a cursor without passing arguments** + + In addition to the cursor constants available and described above, + you can also call ``pygame.cursors.Cursor()``, and your cursor is ready (doing that is the same as + calling ``pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW)``. + Doing one of those calls actually creates a system cursor using the default native image. + + **Creating a color cursor** + + To create a color cursor, create a ``Cursor`` from a ``hotspot`` and a ``surface``. + ``hotspot`` is an (x,y) coordinate that determines where in the cursor the exact point is. + The hotspot position must be within the bounds of the ``surface``. + + **Creating a bitmap cursor** + + When the mouse cursor is visible, it will be displayed as a black and white + bitmap using the given bitmask arrays. The ``size`` is a sequence containing + the cursor width and height. ``hotspot`` is a sequence containing the cursor + hotspot position. + + A cursor has a width and height, but a mouse position is represented by a + set of point coordinates. So the value passed into the cursor ``hotspot`` + variable helps pygame to actually determine at what exact point the cursor + is at. + + ``xormasks`` is a sequence of bytes containing the cursor xor data masks. + Lastly ``andmasks``, a sequence of bytes containing the cursor bitmask data. + To create these variables, we can make use of the + :func:`pygame.cursors.compile()` function. + + Width and height must be a multiple of 8, and the mask arrays must be the + correct size for the given width and height. Otherwise an exception is raised. + + .. method:: copy + + | :sl:`copy the current cursor` + | :sg:`copy() -> Cursor` + + Returns a new Cursor object with the same data and hotspot as the original. + .. ## pygame.cursors.Cursor.copy ## + + + .. attribute:: type + + | :sl:`Gets the cursor type` + | :sg:`type -> string` + + The type will be ``"system"``, ``"bitmap"``, or ``"color"``. + + .. ## pygame.cursors.Cursor.type ## + + .. attribute:: data + + | :sl:`Gets the cursor data` + | :sg:`data -> tuple` + + Returns the data that was used to create this cursor object, wrapped up in a tuple. + + .. ## pygame.cursors.Cursor.data ## + + .. versionadded:: 2.0.1 + + .. ## pygame.cursors.Cursor ## + +.. ## pygame.cursors ## + +Example code for creating and settings cursors. (Click the mouse to switch cursor) + +.. literalinclude:: code_examples/cursors_module_example.py diff --git a/docs/ref/display.rst b/docs/ref/display.rst new file mode 100644 index 0000000..c669eab --- /dev/null +++ b/docs/ref/display.rst @@ -0,0 +1,737 @@ +.. include:: common.txt + +:mod:`pygame.display` +===================== + +.. module:: pygame.display + :synopsis: pygame module to control the display window and screen + +| :sl:`pygame module to control the display window and screen` + +This module offers control over the pygame display. Pygame has a single display +Surface that is either contained in a window or runs full screen. Once you +create the display you treat it as a regular Surface. Changes are not +immediately visible onscreen; you must choose one of the two flipping functions +to update the actual display. + +The origin of the display, where x = 0 and y = 0, is the top left of the +screen. Both axes increase positively towards the bottom right of the screen. + +The pygame display can actually be initialized in one of several modes. By +default, the display is a basic software driven framebuffer. You can request +special modules like automatic scaling or OpenGL support. These are +controlled by flags passed to ``pygame.display.set_mode()``. + +Pygame can only have a single display active at any time. Creating a new one +with ``pygame.display.set_mode()`` will close the previous display. To detect +the number and size of attached screens, you can use +``pygame.display.get_desktop_sizes`` and then select appropriate window size +and display index to pass to ``pygame.display.set_mode()``. + +For backward compatibility ``pygame.display`` allows precise control over +the pixel format or display resolutions. This used to be necessary with old +graphics cards and CRT screens, but is usually not needed any more. Use the +functions ``pygame.display.mode_ok()``, ``pygame.display.list_modes()``, and +``pygame.display.Info()`` to query detailed information about the display. + +Once the display Surface is created, the functions from this module affect the +single existing display. The Surface becomes invalid if the module is +uninitialized. If a new display mode is set, the existing Surface will +automatically switch to operate on the new display. + +When the display mode is set, several events are placed on the pygame event +queue. ``pygame.QUIT`` is sent when the user has requested the program to +shut down. The window will receive ``pygame.ACTIVEEVENT`` events as the display +gains and loses input focus. If the display is set with the +``pygame.RESIZABLE`` flag, ``pygame.VIDEORESIZE`` events will be sent when the +user adjusts the window dimensions. Hardware displays that draw direct to the +screen will get ``pygame.VIDEOEXPOSE`` events when portions of the window must +be redrawn. + +A new windowevent API was introduced in pygame 2.0.1. Check event module docs +for more information on that + +Some display environments have an option for automatically stretching all +windows. When this option is enabled, this automatic stretching distorts the +appearance of the pygame window. In the pygame examples directory, there is +example code (prevent_display_stretching.py) which shows how to disable this +automatic stretching of the pygame display on Microsoft Windows (Vista or newer +required). + +.. function:: init + + | :sl:`Initialize the display module` + | :sg:`init() -> None` + + Initializes the pygame display module. The display module cannot do anything + until it is initialized. This is usually handled for you automatically when + you call the higher level ``pygame.init()``. + + Pygame will select from one of several internal display backends when it is + initialized. The display mode will be chosen depending on the platform and + permissions of current user. Before the display module is initialized the + environment variable ``SDL_VIDEODRIVER`` can be set to control which backend + is used. The systems with multiple choices are listed here. + + :: + + Windows : windib, directx + Unix : x11, dga, fbcon, directfb, ggi, vgl, svgalib, aalib + + On some platforms it is possible to embed the pygame display into an already + existing window. To do this, the environment variable ``SDL_WINDOWID`` must + be set to a string containing the window id or handle. The environment + variable is checked when the pygame display is initialized. Be aware that + there can be many strange side effects when running in an embedded display. + + It is harmless to call this more than once, repeated calls have no effect. + + .. ## pygame.display.init ## + +.. function:: quit + + | :sl:`Uninitialize the display module` + | :sg:`quit() -> None` + + This will shut down the entire display module. This means any active + displays will be closed. This will also be handled automatically when the + program exits. + + It is harmless to call this more than once, repeated calls have no effect. + + .. ## pygame.display.quit ## + +.. function:: get_init + + | :sl:`Returns True if the display module has been initialized` + | :sg:`get_init() -> bool` + + Returns True if the :mod:`pygame.display` module is currently initialized. + + .. ## pygame.display.get_init ## + +.. function:: set_mode + + | :sl:`Initialize a window or screen for display` + | :sg:`set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface` + + This function will create a display Surface. The arguments passed in are + requests for a display type. The actual created display will be the best + possible match supported by the system. + + Note that calling this function implicitly initializes ``pygame.display``, if + it was not initialized before. + + The size argument is a pair of numbers representing the width and + height. The flags argument is a collection of additional options. The depth + argument represents the number of bits to use for color. + + The Surface that gets returned can be drawn to like a regular Surface but + changes will eventually be seen on the monitor. + + If no size is passed or is set to ``(0, 0)`` and pygame uses ``SDL`` + version 1.2.10 or above, the created Surface will have the same size as the + current screen resolution. If only the width or height are set to ``0``, the + Surface will have the same width or height as the screen resolution. Using a + ``SDL`` version prior to 1.2.10 will raise an exception. + + It is usually best to not pass the depth argument. It will default to the + best and fastest color depth for the system. If your game requires a + specific color format you can control the depth with this argument. Pygame + will emulate an unavailable color depth which can be slow. + + When requesting fullscreen display modes, sometimes an exact match for the + requested size cannot be made. In these situations pygame will select + the closest compatible match. The returned surface will still always match + the requested size. + + On high resolution displays(4k, 1080p) and tiny graphics games (640x480) + show up very small so that they are unplayable. SCALED scales up the window + for you. The game thinks it's a 640x480 window, but really it can be bigger. + Mouse events are scaled for you, so your game doesn't need to do it. Note + that SCALED is considered an experimental API and may change in future + releases. + + The flags argument controls which type of display you want. There are + several to choose from, and you can even combine multiple types using the + bitwise or operator, (the pipe "|" character). Here are the display + flags you will want to choose from: + + :: + + pygame.FULLSCREEN create a fullscreen display + pygame.DOUBLEBUF only applicable with OPENGL + pygame.HWSURFACE (obsolete in pygame 2) hardware accelerated, only in FULLSCREEN + pygame.OPENGL create an OpenGL-renderable display + pygame.RESIZABLE display window should be sizeable + pygame.NOFRAME display window will have no border or controls + pygame.SCALED resolution depends on desktop size and scale graphics + pygame.SHOWN window is opened in visible mode (default) + pygame.HIDDEN window is opened in hidden mode + + + .. versionadded:: 2.0.0 ``SCALED``, ``SHOWN`` and ``HIDDEN`` + + By setting the ``vsync`` parameter to ``1``, it is possible to get a display + with vertical sync, but you are not guaranteed to get one. The request only + works at all for calls to ``set_mode()`` with the ``pygame.OPENGL`` or + ``pygame.SCALED`` flags set, and is still not guaranteed even with one of + those set. What you get depends on the hardware and driver configuration + of the system pygame is running on. Here is an example usage of a call + to ``set_mode()`` that may give you a display with vsync: + + :: + + flags = pygame.OPENGL | pygame.FULLSCREEN + window_surface = pygame.display.set_mode((1920, 1080), flags, vsync=1) + + Vsync behaviour is considered experimental, and may change in future releases. + + .. versionadded:: 2.0.0 ``vsync`` + + Basic example: + + :: + + # Open a window on the screen + screen_width=700 + screen_height=400 + screen=pygame.display.set_mode([screen_width, screen_height]) + + The display index ``0`` means the default display is used. If no display + index argument is provided, the default display can be overridden with an + environment variable. + + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. versionchanged:: 2.1.3 + pygame now ensures that subsequent calls to this function clears the + window to black. On older versions, this was an implementation detail + on the major platforms this function was tested with. + + .. ## pygame.display.set_mode ## + +.. function:: get_surface + + | :sl:`Get a reference to the currently set display surface` + | :sg:`get_surface() -> Surface` + + Return a reference to the currently set display Surface. If no display mode + has been set this will return None. + + .. ## pygame.display.get_surface ## + +.. function:: flip + + | :sl:`Update the full display Surface to the screen` + | :sg:`flip() -> None` + + This will update the contents of the entire display. If your display mode is + using the flags ``pygame.HWSURFACE`` and ``pygame.DOUBLEBUF`` on pygame 1, + this will wait for a vertical retrace and swap the surfaces. + + When using an ``pygame.OPENGL`` display mode this will perform a gl buffer + swap. + + .. ## pygame.display.flip ## + +.. function:: update + + | :sl:`Update portions of the screen for software displays` + | :sg:`update(rectangle=None) -> None` + | :sg:`update(rectangle_list) -> None` + + This function is like an optimized version of ``pygame.display.flip()`` for + software displays. It allows only a portion of the screen to be updated, + instead of the entire area. If no argument is passed it updates the entire + Surface area like ``pygame.display.flip()``. + + Note that calling ``display.update(None)`` means no part of the window is + updated. Whereas ``display.update()`` means the whole window is updated. + + You can pass the function a single rectangle, or a sequence of rectangles. + It is more efficient to pass many rectangles at once than to call update + multiple times with single or a partial list of rectangles. If passing a + sequence of rectangles it is safe to include None values in the list, which + will be skipped. + + This call cannot be used on ``pygame.OPENGL`` displays and will generate an + exception. + + .. ## pygame.display.update ## + +.. function:: get_driver + + | :sl:`Get the name of the pygame display backend` + | :sg:`get_driver() -> name` + + Pygame chooses one of many available display backends when it is + initialized. This returns the internal name used for the display backend. + This can be used to provide limited information about what display + capabilities might be accelerated. See the ``SDL_VIDEODRIVER`` flags in + ``pygame.display.set_mode()`` to see some of the common options. + + .. ## pygame.display.get_driver ## + +.. function:: Info + + | :sl:`Create a video display information object` + | :sg:`Info() -> VideoInfo` + + Creates a simple object containing several attributes to describe the + current graphics environment. If this is called before + ``pygame.display.set_mode()`` some platforms can provide information about + the default display mode. This can also be called after setting the display + mode to verify specific display options were satisfied. The VidInfo object + has several attributes: + + :: + + hw: 1 if the display is hardware accelerated + wm: 1 if windowed display modes can be used + video_mem: The megabytes of video memory on the display. This is 0 if + unknown + bitsize: Number of bits used to store each pixel + bytesize: Number of bytes used to store each pixel + masks: Four values used to pack RGBA values into pixels + shifts: Four values used to pack RGBA values into pixels + losses: Four values used to pack RGBA values into pixels + blit_hw: 1 if hardware Surface blitting is accelerated + blit_hw_CC: 1 if hardware Surface colorkey blitting is accelerated + blit_hw_A: 1 if hardware Surface pixel alpha blitting is accelerated + blit_sw: 1 if software Surface blitting is accelerated + blit_sw_CC: 1 if software Surface colorkey blitting is accelerated + blit_sw_A: 1 if software Surface pixel alpha blitting is accelerated + current_h, current_w: Height and width of the current video mode, or + of the desktop mode if called before the display.set_mode + is called. (current_h, current_w are available since + SDL 1.2.10, and pygame 1.8.0). They are -1 on error, or if + an old SDL is being used. + + .. ## pygame.display.Info ## + +.. function:: get_wm_info + + | :sl:`Get information about the current windowing system` + | :sg:`get_wm_info() -> dict` + + Creates a dictionary filled with string keys. The strings and values are + arbitrarily created by the system. Some systems may have no information and + an empty dictionary will be returned. Most platforms will return a "window" + key with the value set to the system id for the current display. + + .. versionadded:: 1.7.1 + + .. ## pygame.display.get_wm_info ## + +.. function:: get_desktop_sizes + + | :sl:`Get sizes of active desktops` + | :sg:`get_desktop_sizes() -> list` + + This function returns the sizes of the currently configured + virtual desktops as a list of (x, y) tuples of integers. + + The length of the list is not the same as the number of attached monitors, + as a desktop can be mirrored across multiple monitors. The desktop sizes + do not indicate the maximum monitor resolutions supported by the hardware, + but the desktop size configured in the operating system. + + In order to fit windows into the desktop as it is currently configured, and + to respect the resolution configured by the operating system in fullscreen + mode, this function *should* be used to replace many use cases of + ``pygame.display.list_modes()`` whenever applicable. + + .. versionadded:: 2.0.0 + +.. function:: list_modes + + | :sl:`Get list of available fullscreen modes` + | :sg:`list_modes(depth=0, flags=pygame.FULLSCREEN, display=0) -> list` + + This function returns a list of possible sizes for a specified color + depth. The return value will be an empty list if no display modes are + available with the given arguments. A return value of ``-1`` means that + any requested size should work (this is likely the case for windowed + modes). Mode sizes are sorted from biggest to smallest. + + If depth is ``0``, the current/best color depth for the display is used. + The flags defaults to ``pygame.FULLSCREEN``, but you may need to add + additional flags for specific fullscreen modes. + + The display index ``0`` means the default display is used. + + Since pygame 2.0, ``pygame.display.get_desktop_sizes()`` has taken over + some use cases from ``pygame.display.list_modes()``: + + To find a suitable size for non-fullscreen windows, it is preferable to + use ``pygame.display.get_desktop_sizes()`` to get the size of the *current* + desktop, and to then choose a smaller window size. This way, the window is + guaranteed to fit, even when the monitor is configured to a lower resolution + than the maximum supported by the hardware. + + To avoid changing the physical monitor resolution, it is also preferable to + use ``pygame.display.get_desktop_sizes()`` to determine the fullscreen + resolution. Developers are strongly advised to default to the current + physical monitor resolution unless the user explicitly requests a different + one (e.g. in an options menu or configuration file). + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. ## pygame.display.list_modes ## + +.. function:: mode_ok + + | :sl:`Pick the best color depth for a display mode` + | :sg:`mode_ok(size, flags=0, depth=0, display=0) -> depth` + + This function uses the same arguments as ``pygame.display.set_mode()``. It + is used to determine if a requested display mode is available. It will + return ``0`` if the display mode cannot be set. Otherwise it will return a + pixel depth that best matches the display asked for. + + Usually the depth argument is not passed, but some platforms can support + multiple display depths. If passed it will hint to which depth is a better + match. + + The function will return ``0`` if the passed display flags cannot be set. + + The display index ``0`` means the default display is used. + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. ## pygame.display.mode_ok ## + +.. function:: gl_get_attribute + + | :sl:`Get the value for an OpenGL flag for the current display` + | :sg:`gl_get_attribute(flag) -> value` + + After calling ``pygame.display.set_mode()`` with the ``pygame.OPENGL`` flag, + it is a good idea to check the value of any requested OpenGL attributes. See + ``pygame.display.gl_set_attribute()`` for a list of valid flags. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## pygame.display.gl_get_attribute ## + +.. function:: gl_set_attribute + + | :sl:`Request an OpenGL display attribute for the display mode` + | :sg:`gl_set_attribute(flag, value) -> None` + + When calling ``pygame.display.set_mode()`` with the ``pygame.OPENGL`` flag, + Pygame automatically handles setting the OpenGL attributes like color and + double-buffering. OpenGL offers several other attributes you may want control + over. Pass one of these attributes as the flag, and its appropriate value. + This must be called before ``pygame.display.set_mode()``. + + Many settings are the requested minimum. Creating a window with an OpenGL context + will fail if OpenGL cannot provide the requested attribute, but it may for example + give you a stencil buffer even if you request none, or it may give you a larger + one than requested. + + The ``OPENGL`` flags are: + + :: + + GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_ACCUM_RED_SIZE, + GL_ACCUM_GREEN_SIZE, GL_ACCUM_BLUE_SIZE, GL_ACCUM_ALPHA_SIZE, + GL_MULTISAMPLEBUFFERS, GL_MULTISAMPLESAMPLES, GL_STEREO + + :const:`GL_MULTISAMPLEBUFFERS` + + Whether to enable multisampling anti-aliasing. + Defaults to 0 (disabled). + + Set ``GL_MULTISAMPLESAMPLES`` to a value + above 0 to control the amount of anti-aliasing. + A typical value is 2 or 3. + + :const:`GL_STENCIL_SIZE` + + Minimum bit size of the stencil buffer. Defaults to 0. + + :const:`GL_DEPTH_SIZE` + + Minimum bit size of the depth buffer. Defaults to 16. + + :const:`GL_STEREO` + + 1 enables stereo 3D. Defaults to 0. + + :const:`GL_BUFFER_SIZE` + + Minimum bit size of the frame buffer. Defaults to 0. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. versionadded:: 2.0.0 Additional attributes: + + :: + + GL_ACCELERATED_VISUAL, + GL_CONTEXT_MAJOR_VERSION, GL_CONTEXT_MINOR_VERSION, + GL_CONTEXT_FLAGS, GL_CONTEXT_PROFILE_MASK, + GL_SHARE_WITH_CURRENT_CONTEXT, + GL_CONTEXT_RELEASE_BEHAVIOR, + GL_FRAMEBUFFER_SRGB_CAPABLE + + :const:`GL_CONTEXT_PROFILE_MASK` + + Sets the OpenGL profile to one of these values: + + :: + + GL_CONTEXT_PROFILE_CORE disable deprecated features + GL_CONTEXT_PROFILE_COMPATIBILITY allow deprecated features + GL_CONTEXT_PROFILE_ES allow only the ES feature + subset of OpenGL + + :const:`GL_ACCELERATED_VISUAL` + + Set to 1 to require hardware acceleration, or 0 to force software render. + By default, both are allowed. + + .. ## pygame.display.gl_set_attribute ## + +.. function:: get_active + + | :sl:`Returns True when the display is active on the screen` + | :sg:`get_active() -> bool` + + Returns True when the display Surface is considered actively + renderable on the screen and may be visible to the user. This is + the default state immediately after ``pygame.display.set_mode()``. + This method may return True even if the application is fully hidden + behind another application window. + + This will return False if the display Surface has been iconified or + minimized (either via ``pygame.display.iconify()`` or via an OS + specific method such as the minimize-icon available on most + desktops). + + The method can also return False for other reasons without the + application being explicitly iconified or minimized by the user. A + notable example being if the user has multiple virtual desktops and + the display Surface is not on the active virtual desktop. + + .. note:: This function returning True is unrelated to whether the + application has input focus. Please see + ``pygame.key.get_focused()`` and ``pygame.mouse.get_focused()`` + for APIs related to input focus. + + .. ## pygame.display.get_active ## + +.. function:: iconify + + | :sl:`Iconify the display surface` + | :sg:`iconify() -> bool` + + Request the window for the display surface be iconified or hidden. Not all + systems and displays support an iconified display. The function will return + True if successful. + + When the display is iconified ``pygame.display.get_active()`` will return + ``False``. The event queue should receive an ``ACTIVEEVENT`` event when the + window has been iconified. Additionally, the event queue also receives a + ``WINDOWEVENT_MINIMIZED`` event when the window has been iconified on pygame 2. + + .. ## pygame.display.iconify ## + +.. function:: toggle_fullscreen + + | :sl:`Switch between fullscreen and windowed displays` + | :sg:`toggle_fullscreen() -> int` + + Switches the display window between windowed and fullscreen modes. + Display driver support is not great when using pygame 1, but with + pygame 2 it is the most reliable method to switch to and from fullscreen. + + Supported display drivers in pygame 1: + + * x11 (Linux/Unix) + * wayland (Linux/Unix) + + Supported display drivers in pygame 2: + + * windows (Windows) + * x11 (Linux/Unix) + * wayland (Linux/Unix) + * cocoa (OSX/Mac) + + .. Note:: :func:`toggle_fullscreen` doesn't work on Windows + unless the window size is in :func:`pygame.display.list_modes()` or + the window is created with the flag ``pygame.SCALED``. + See `issue #2380 `_. + + .. ## pygame.display.toggle_fullscreen ## + +.. function:: set_gamma + + | :sl:`Change the hardware gamma ramps` + | :sg:`set_gamma(red, green=None, blue=None) -> bool` + + DEPRECATED: This functionality will go away in SDL3. + + Set the red, green, and blue gamma values on the display hardware. If the + green and blue arguments are not passed, they will both be the same as red. + Not all systems and hardware support gamma ramps, if the function succeeds + it will return ``True``. + + A gamma value of ``1.0`` creates a linear color table. Lower values will + darken the display and higher values will brighten. + + .. deprecated:: 2.2.0 + + .. ## pygame.display.set_gamma ## + +.. function:: set_gamma_ramp + + | :sl:`Change the hardware gamma ramps with a custom lookup` + | :sg:`set_gamma_ramp(red, green, blue) -> bool` + + DEPRECATED: This functionality will go away in SDL3. + + Set the red, green, and blue gamma ramps with an explicit lookup table. Each + argument should be sequence of 256 integers. The integers should range + between ``0`` and ``0xffff``. Not all systems and hardware support gamma + ramps, if the function succeeds it will return ``True``. + + .. deprecated:: 2.2.0 + + .. ## pygame.display.set_gamma_ramp ## + +.. function:: set_icon + + | :sl:`Change the system image for the display window` + | :sg:`set_icon(Surface) -> None` + + Sets the runtime icon the system will use to represent the display window. + All windows default to a simple pygame logo for the window icon. + + Note that calling this function implicitly initializes ``pygame.display``, if + it was not initialized before. + + You can pass any surface, but most systems want a smaller image around + 32x32. The image can have colorkey transparency which will be passed to the + system. + + Some systems do not allow the window icon to change after it has been shown. + This function can be called before ``pygame.display.set_mode()`` to create + the icon before the display mode is set. + + .. ## pygame.display.set_icon ## + +.. function:: set_caption + + | :sl:`Set the current window caption` + | :sg:`set_caption(title, icontitle=None) -> None` + + If the display has a window title, this function will change the name on the + window. In pygame 1.x, some systems supported an alternate shorter title to + be used for minimized displays, but in pygame 2 ``icontitle`` does nothing. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## pygame.display.set_caption ## + +.. function:: get_caption + + | :sl:`Get the current window caption` + | :sg:`get_caption() -> (title, icontitle)` + + Returns the title and icontitle for the display window. In pygame 2.x + these will always be the same value. + + .. ## pygame.display.get_caption ## + +.. function:: set_palette + + | :sl:`Set the display color palette for indexed displays` + | :sg:`set_palette(palette=None) -> None` + + This will change the video display color palette for 8-bit displays. This + does not change the palette for the actual display Surface, only the palette + that is used to display the Surface. If no palette argument is passed, the + system default palette will be restored. The palette is a sequence of + ``RGB`` triplets. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## pygame.display.set_palette ## + +.. function:: get_num_displays + + | :sl:`Return the number of displays` + | :sg:`get_num_displays() -> int` + + Returns the number of available displays. This is always 1 if + :func:`pygame.get_sdl_version()` returns a major version number below 2. + + .. versionadded:: 1.9.5 + + .. ## pygame.display.get_num_displays ## + +.. function:: get_window_size + + | :sl:`Return the size of the window or screen` + | :sg:`get_window_size() -> tuple` + + Returns the size of the window initialized with :func:`pygame.display.set_mode()`. + This may differ from the size of the display surface if ``SCALED`` is used. + + .. versionadded:: 2.0.0 + + .. ## pygame.display.get_window_size ## + +.. function:: get_allow_screensaver + + | :sl:`Return whether the screensaver is allowed to run.` + | :sg:`get_allow_screensaver() -> bool` + + Return whether screensaver is allowed to run whilst the app is running. + Default is ``False``. + By default pygame does not allow the screensaver during game play. + + .. note:: Some platforms do not have a screensaver or support + disabling the screensaver. Please see + :func:`pygame.display.set_allow_screensaver()` for + caveats with screensaver support. + + .. versionadded:: 2.0.0 + + .. ## pygame.display.get_allow_screensaver ## + +.. function:: set_allow_screensaver + + | :sl:`Set whether the screensaver may run` + | :sg:`set_allow_screensaver(bool) -> None` + + Change whether screensavers should be allowed whilst the app is running. + The default value of the argument to the function is True. + By default pygame does not allow the screensaver during game play. + + If the screensaver has been disallowed due to this function, it will automatically + be allowed to run when :func:`pygame.quit()` is called. + + It is possible to influence the default value via the environment variable + ``SDL_HINT_VIDEO_ALLOW_SCREENSAVER``, which can be set to either ``0`` (disable) + or ``1`` (enable). + + .. note:: Disabling screensaver is subject to platform support. + When platform support is absent, this function will + silently appear to work even though the screensaver state + is unchanged. The lack of feedback is due to SDL not + providing any supported method for determining whether + it supports changing the screensaver state. + ``SDL_HINT_VIDEO_ALLOW_SCREENSAVER`` is available in SDL 2.0.2 or later. + SDL1.2 does not implement this. + + .. versionadded:: 2.0.0 + + + .. ## pygame.display.set_allow_screensaver ## + +.. ## pygame.display ## diff --git a/docs/ref/draw.rst b/docs/ref/draw.rst new file mode 100644 index 0000000..a759860 --- /dev/null +++ b/docs/ref/draw.rst @@ -0,0 +1,557 @@ +.. include:: common.txt + +:mod:`pygame.draw` +================== + +.. module:: pygame.draw + :synopsis: pygame module for drawing shapes + +| :sl:`pygame module for drawing shapes` + +Draw several simple shapes to a surface. These functions will work for +rendering to any format of surface. + +Most of the functions take a width argument to represent the size of stroke +(thickness) around the edge of the shape. If a width of 0 is passed the shape +will be filled (solid). + +All the drawing functions respect the clip area for the surface and will be +constrained to that area. The functions return a rectangle representing the +bounding area of changed pixels. This bounding rectangle is the 'minimum' +bounding box that encloses the affected area. + +All the drawing functions accept a color argument that can be one of the +following formats: + + - a :mod:`pygame.Color` object + - an ``(RGB)`` triplet (tuple/list) + - an ``(RGBA)`` quadruplet (tuple/list) + - an integer value that has been mapped to the surface's pixel format + (see :func:`pygame.Surface.map_rgb` and :func:`pygame.Surface.unmap_rgb`) + +A color's alpha value will be written directly into the surface (if the +surface contains pixel alphas), but the draw function will not draw +transparently. + +These functions temporarily lock the surface they are operating on. Many +sequential drawing calls can be sped up by locking and unlocking the surface +object around the draw calls (see :func:`pygame.Surface.lock` and +:func:`pygame.Surface.unlock`). + +.. note :: + See the :mod:`pygame.gfxdraw` module for alternative draw methods. + + +.. function:: rect + + | :sl:`draw a rectangle` + | :sg:`rect(surface, color, rect) -> Rect` + | :sg:`rect(surface, color, rect, width=0, border_radius=0, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1, border_bottom_right_radius=-1) -> Rect` + + Draws a rectangle on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to draw, position and dimensions + :param int width: (optional) used for line thickness or to indicate that + the rectangle is to be filled (not to be confused with the width value + of the ``rect`` parameter) + + | if ``width == 0``, (default) fill the rectangle + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. versionchanged:: 2.1.1 + Drawing rects with width now draws the width correctly inside the + rect's area, rather than using an internal call to draw.lines(), + which had half the width spill outside the rect area. + + :param int border_radius: (optional) used for drawing rectangle with rounded corners. + The supported range is [0, min(height, width) / 2], with 0 representing a rectangle + without rounded corners. + :param int border_top_left_radius: (optional) used for setting the value of top left + border. If you don't set this value, it will use the border_radius value. + :param int border_top_right_radius: (optional) used for setting the value of top right + border. If you don't set this value, it will use the border_radius value. + :param int border_bottom_left_radius: (optional) used for setting the value of bottom left + border. If you don't set this value, it will use the border_radius value. + :param int border_bottom_right_radius: (optional) used for setting the value of bottom right + border. If you don't set this value, it will use the border_radius value. + + | if ``border_radius < 1`` it will draw rectangle without rounded corners + | if any of border radii has the value ``< 0`` it will use value of the border_radius + | If sum of radii on the same side of the rectangle is greater than the rect size the radii + | will get scaled + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. note:: + The :func:`pygame.Surface.fill()` method works just as well for drawing + filled rectangles and can be hardware accelerated on some platforms. + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + .. versionchanged:: 2.0.0.dev8 Added support for border radius. + + .. ## pygame.draw.rect ## + +.. function:: polygon + + | :sl:`draw a polygon` + | :sg:`polygon(surface, color, points) -> Rect` + | :sg:`polygon(surface, color, points, width=0) -> Rect` + + Draws a polygon on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param points: a sequence of 3 or more (x, y) coordinates that make up the + vertices of the polygon, each *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats, + e.g. ``[(x1, y1), (x2, y2), (x3, y3)]`` + :type points: tuple(coordinate) or list(coordinate) + :param int width: (optional) used for line thickness or to indicate that + the polygon is to be filled + + | if width == 0, (default) fill the polygon + | if width > 0, used for line thickness + | if width < 0, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will grow + outside the original boundary of the polygon. For more details on + how the thickness for edge lines grow, refer to the ``width`` notes + of the :func:`pygame.draw.line` function. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. note:: + For an aapolygon, use :func:`aalines()` with ``closed=True``. + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.polygon ## + +.. function:: circle + + | :sl:`draw a circle` + | :sg:`circle(surface, color, center, radius) -> Rect` + | :sg:`circle(surface, color, center, radius, width=0, draw_top_right=None, draw_top_left=None, draw_bottom_left=None, draw_bottom_right=None) -> Rect` + + Draws a circle on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param center: center point of the circle as a sequence of 2 ints/floats, + e.g. ``(x, y)`` + :type center: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param radius: radius of the circle, measured from the ``center`` parameter, + nothing will be drawn if the ``radius`` is less than 1 + :type radius: int or float + :param int width: (optional) used for line thickness or to indicate that + the circle is to be filled + + | if ``width == 0``, (default) fill the circle + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward. + :param bool draw_top_right: (optional) if this is set to True then the top right corner + of the circle will be drawn + :param bool draw_top_left: (optional) if this is set to True then the top left corner + of the circle will be drawn + :param bool draw_bottom_left: (optional) if this is set to True then the bottom left corner + of the circle will be drawn + :param bool draw_bottom_right: (optional) if this is set to True then the bottom right corner + of the circle will be drawn + + | if any of the draw_circle_part is True then it will draw all circle parts that have the True + | value, otherwise it will draw the entire circle. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``center`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``center`` is not a sequence of two numbers + :raises TypeError: if ``radius`` is not a number + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + Nothing is drawn when the radius is 0 (a pixel at the ``center`` coordinates + used to be drawn when the radius equaled 0). + Floats, and Vector2 are accepted for the ``center`` param. + The drawing algorithm was improved to look more like a circle. + .. versionchanged:: 2.0.0.dev8 Added support for drawing circle quadrants. + + .. ## pygame.draw.circle ## + +.. function:: ellipse + + | :sl:`draw an ellipse` + | :sg:`ellipse(surface, color, rect) -> Rect` + | :sg:`ellipse(surface, color, rect, width=0) -> Rect` + + Draws an ellipse on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to indicate the position and dimensions of the + ellipse, the ellipse will be centered inside the rectangle and bounded + by it + :param int width: (optional) used for line thickness or to indicate that + the ellipse is to be filled (not to be confused with the width value + of the ``rect`` parameter) + + | if ``width == 0``, (default) fill the ellipse + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward from the original boundary of the ``rect`` parameter. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.ellipse ## + +.. function:: arc + + | :sl:`draw an elliptical arc` + | :sg:`arc(surface, color, rect, start_angle, stop_angle) -> Rect` + | :sg:`arc(surface, color, rect, start_angle, stop_angle, width=1) -> Rect` + + Draws an elliptical arc on the given surface. + + The two angle arguments are given in radians and indicate the start and stop + positions of the arc. The arc is drawn in a counterclockwise direction from + the ``start_angle`` to the ``stop_angle``. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to indicate the position and dimensions of the + ellipse which the arc will be based on, the ellipse will be centered + inside the rectangle + :param float start_angle: start angle of the arc in radians + :param float stop_angle: stop angle of the arc in + radians + + | if ``start_angle < stop_angle``, the arc is drawn in a + counterclockwise direction from the ``start_angle`` to the + ``stop_angle`` + | if ``start_angle > stop_angle``, tau (tau == 2 * pi) will be added + to the ``stop_angle``, if the resulting stop angle value is greater + than the ``start_angle`` the above ``start_angle < stop_angle`` case + applies, otherwise nothing will be drawn + | if ``start_angle == stop_angle``, nothing will be drawn + | + + :param int width: (optional) used for line thickness (not to be confused + with the width value of the ``rect`` parameter) + + | if ``width == 0``, nothing will be drawn + | if ``width > 0``, (default is 1) used for line thickness + | if ``width < 0``, same as ``width == 0`` + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward from the original boundary of the ``rect`` parameter. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.arc ## + +.. function:: line + + | :sl:`draw a straight line` + | :sg:`line(surface, color, start_pos, end_pos) -> Rect` + | :sg:`line(surface, color, start_pos, end_pos, width=1) -> Rect` + + Draws a straight line on the given surface. There are no endcaps. For thick + lines the ends are squared off. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param start_pos: start position of the line, (x, y) + :type start_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param end_pos: end position of the line, (x, y) + :type end_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param int width: (optional) used for line thickness + + | if width >= 1, used for line thickness (default is 1) + | if width < 1, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, lines will grow as follows. + + For odd ``width`` values, the thickness of each line grows with the + original line being in the center. + + For even ``width`` values, the thickness of each line grows with the + original line being offset from the center (as there is no exact + center line drawn). As a result, lines with a slope < 1 + (horizontal-ish) will have 1 more pixel of thickness below the + original line (in the y direction). Lines with a slope >= 1 + (vertical-ish) will have 1 more pixel of thickness to the right of + the original line (in the x direction). + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``start_pos`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``start_pos`` or ``end_pos`` is not a sequence of + two numbers + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.line ## + +.. function:: lines + + | :sl:`draw multiple contiguous straight line segments` + | :sg:`lines(surface, color, closed, points) -> Rect` + | :sg:`lines(surface, color, closed, points, width=1) -> Rect` + + Draws a sequence of contiguous straight lines on the given surface. There are + no endcaps or miter joints. For thick lines the ends are squared off. + Drawing thick lines with sharp corners can have undesired looking results. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param bool closed: if ``True`` an additional line segment is drawn between + the first and last points in the ``points`` sequence + :param points: a sequence of 2 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats and adjacent + coordinates will be connected by a line segment, e.g. for the + points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will be drawn + from ``(x1, y1)`` to ``(x2, y2)`` and from ``(x2, y2)`` to ``(x3, y3)``, + additionally if the ``closed`` parameter is ``True`` another line segment + will be drawn from ``(x3, y3)`` to ``(x1, y1)`` + :type points: tuple(coordinate) or list(coordinate) + :param int width: (optional) used for line thickness + + | if width >= 1, used for line thickness (default is 1) + | if width < 1, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1`` refer to the ``width`` notes + of :func:`line` for details on how thick lines grow. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 2`` (must have at least 2 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.lines ## + +.. function:: aaline + + | :sl:`draw a straight antialiased line` + | :sg:`aaline(surface, color, start_pos, end_pos) -> Rect` + | :sg:`aaline(surface, color, start_pos, end_pos, blend=1) -> Rect` + + Draws a straight antialiased line on the given surface. + + The line has a thickness of one pixel and the endpoints have a height and + width of one pixel each. + + The way a line and its endpoints are drawn: + If both endpoints are equal, only a single pixel is drawn (after + rounding floats to nearest integer). + + Otherwise if the line is not steep (i.e. if the length along the x-axis + is greater than the height along the y-axis): + + For each endpoint: + + If ``x``, the endpoint's x-coordinate, is a whole number find + which pixels would be covered by it and draw them. + + Otherwise: + + Calculate the position of the nearest point with a whole number + for its x-coordinate, when extending the line past the + endpoint. + + Find which pixels would be covered and how much by that point. + + If the endpoint is the left one, multiply the coverage by (1 - + the decimal part of ``x``). + + Otherwise multiply the coverage by the decimal part of ``x``. + + Then draw those pixels. + + *e.g.:* + | The left endpoint of the line ``((1, 1.3), (5, 3))`` would + cover 70% of the pixel ``(1, 1)`` and 30% of the pixel + ``(1, 2)`` while the right one would cover 100% of the + pixel ``(5, 3)``. + | The left endpoint of the line ``((1.2, 1.4), (4.6, 3.1))`` + would cover 56% *(i.e. 0.8 * 70%)* of the pixel ``(1, 1)`` + and 24% *(i.e. 0.8 * 30%)* of the pixel ``(1, 2)`` while + the right one would cover 42% *(i.e. 0.6 * 70%)* of the + pixel ``(5, 3)`` and 18% *(i.e. 0.6 * 30%)* of the pixel + ``(5, 4)`` while the right + + Then for each point between the endpoints, along the line, whose + x-coordinate is a whole number: + + Find which pixels would be covered and how much by that point and + draw them. + + *e.g.:* + | The points along the line ``((1, 1), (4, 2.5))`` would be + ``(2, 1.5)`` and ``(3, 2)`` and would cover 50% of the pixel + ``(2, 1)``, 50% of the pixel ``(2, 2)`` and 100% of the pixel + ``(3, 2)``. + | The points along the line ``((1.2, 1.4), (4.6, 3.1))`` would + be ``(2, 1.8)`` (covering 20% of the pixel ``(2, 1)`` and 80% + of the pixel ``(2, 2)``), ``(3, 2.3)`` (covering 70% of the + pixel ``(3, 2)`` and 30% of the pixel ``(3, 3)``) and ``(4, + 2.8)`` (covering 20% of the pixel ``(2, 1)`` and 80% of the + pixel ``(2, 2)``) + + Otherwise do the same for steep lines as for non-steep lines except + along the y-axis instead of the x-axis (using ``y`` instead of ``x``, + top instead of left and bottom instead of right). + + .. note:: + Regarding float values for coordinates, a point with coordinate + consisting of two whole numbers is considered being right in the center + of said pixel (and having a height and width of 1 pixel would therefore + completely cover it), while a point with coordinate where one (or both) + of the numbers have non-zero decimal parts would be partially covering + two (or four if both numbers have decimal parts) adjacent pixels, *e.g.* + the point ``(1.4, 2)`` covers 60% of the pixel ``(1, 2)`` and 40% of the + pixel ``(2,2)``. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param start_pos: start position of the line, (x, y) + :type start_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param end_pos: end position of the line, (x, y) + :type end_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param int blend: (optional) (deprecated) if non-zero (default) the line will be blended + with the surface's existing pixel shades, otherwise it will overwrite them + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``start_pos`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``start_pos`` or ``end_pos`` is not a sequence of + two numbers + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.aaline ## + +.. function:: aalines + + | :sl:`draw multiple contiguous straight antialiased line segments` + | :sg:`aalines(surface, color, closed, points) -> Rect` + | :sg:`aalines(surface, color, closed, points, blend=1) -> Rect` + + Draws a sequence of contiguous straight antialiased lines on the given + surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param bool closed: if ``True`` an additional line segment is drawn between + the first and last points in the ``points`` sequence + :param points: a sequence of 2 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats and adjacent + coordinates will be connected by a line segment, e.g. for the + points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will be drawn + from ``(x1, y1)`` to ``(x2, y2)`` and from ``(x2, y2)`` to ``(x3, y3)``, + additionally if the ``closed`` parameter is ``True`` another line segment + will be drawn from ``(x3, y3)`` to ``(x1, y1)`` + :type points: tuple(coordinate) or list(coordinate) + :param int blend: (optional) (deprecated) if non-zero (default) each line will be blended + with the surface's existing pixel shades, otherwise the pixels will be + overwritten + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 2`` (must have at least 2 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.aalines ## + +.. ## pygame.draw ## + +.. figure:: code_examples/draw_module_example.png + :alt: draw module example + + Example code for draw module. + +.. literalinclude:: code_examples/draw_module_example.py + diff --git a/docs/ref/event.rst b/docs/ref/event.rst new file mode 100644 index 0000000..aa5b7e7 --- /dev/null +++ b/docs/ref/event.rst @@ -0,0 +1,565 @@ +.. include:: common.txt + +:mod:`pygame.event` +=================== + +.. module:: pygame.event + :synopsis: pygame module for interacting with events and queues + +| :sl:`pygame module for interacting with events and queues` + +Pygame handles all its event messaging through an event queue. The routines in +this module help you manage that event queue. The input queue is heavily +dependent on the :mod:`pygame.display` module. If the display has not been +initialized and a video mode not set, the event queue may not work properly. + +The event queue has an upper limit on the number of events it can hold. When +the queue becomes full new events are quietly dropped. To prevent lost events, +especially input events which signal a quit command, your program must handle +events every frame (with ``pygame.event.get()``, ``pygame.event.pump()``, +``pygame.event.wait()``, ``pygame.event.peek()`` or ``pygame.event.clear()``) +and process them. Not handling events may cause your system to decide your +program has locked up. To speed up queue processing use +:func:`pygame.event.set_blocked()` to limit which events get queued. + +To get the state of various input devices, you can forego the event queue and +access the input devices directly with their appropriate modules: +:mod:`pygame.mouse`, :mod:`pygame.key`, and :mod:`pygame.joystick`. If you use +this method, remember that pygame requires some form of communication with the +system window manager and other parts of the platform. To keep pygame in sync +with the system, you will need to call :func:`pygame.event.pump()` to keep +everything current. Usually, this should be called once per game loop. +Note: Joysticks will not send any events until the device has been initialized. + +The event queue contains :class:`pygame.event.Event` event objects. +There are a variety of ways to access the queued events, from simply +checking for the existence of events, to grabbing them directly off the stack. +The event queue also offers some simple filtering which can slightly help +performance by blocking certain event types from the queue. Use +:func:`pygame.event.set_allowed()` and :func:`pygame.event.set_blocked()` to +change this filtering. By default, all event types can be placed on the queue. + +All :class:`pygame.event.Event` instances contain an event type identifier +and attributes specific to that event type. The event type identifier is +accessible as the :attr:`pygame.event.Event.type` property. Any of the +event specific attributes can be accessed through the +:attr:`pygame.event.Event.__dict__` attribute or directly as an attribute +of the event object (as member lookups are passed through to the object's +dictionary values). The event object has no method functions. Users can create +their own new events with the :func:`pygame.event.Event()` function. + +The event type identifier is in between the values of ``NOEVENT`` and +``NUMEVENTS``. User defined events should have a value in the inclusive range +of ``USEREVENT`` to ``NUMEVENTS - 1``. User defined events can get a custom +event number with :func:`pygame.event.custom_type()`. +It is recommended all user events follow this system. + +Events support equality and inequality comparisons. Two events are equal if +they are the same type and have identical attribute values. + +While debugging and experimenting, you can print an event object for a quick +display of its type and members. The function :func:`pygame.event.event_name()` +can be used to get a string representing the name of the event type. + +Events that come from the system will have a guaranteed set of member +attributes based on the type. The following is a list of event types with their +specific attributes. + +:: + + QUIT none + ACTIVEEVENT gain, state + KEYDOWN key, mod, unicode, scancode + KEYUP key, mod, unicode, scancode + MOUSEMOTION pos, rel, buttons, touch + MOUSEBUTTONUP pos, button, touch + MOUSEBUTTONDOWN pos, button, touch + JOYAXISMOTION joy (deprecated), instance_id, axis, value + JOYBALLMOTION joy (deprecated), instance_id, ball, rel + JOYHATMOTION joy (deprecated), instance_id, hat, value + JOYBUTTONUP joy (deprecated), instance_id, button + JOYBUTTONDOWN joy (deprecated), instance_id, button + VIDEORESIZE size, w, h + VIDEOEXPOSE none + USEREVENT code + +.. versionchanged:: 2.0.0 The ``joy`` attribute was deprecated, ``instance_id`` was added. + +.. versionchanged:: 2.0.1 The ``unicode`` attribute was added to ``KEYUP`` event. + +Note that ``ACTIVEEVENT``, ``VIDEORESIZE`` and ``VIDEOEXPOSE`` are considered +as "legacy" events, the use of pygame2 ``WINDOWEVENT`` API is recommended over +the use of this older API. + +You can also find a list of constants for keyboard keys +:ref:`here `. + +A keyboard event occurs when a key is pressed (``KEYDOWN``) and when a key is released (``KEYUP``) +The ``key`` attribute of keyboard events contains the value of what key was pressed or released. +The ``mod`` attribute contains information about the state of keyboard modifiers (SHIFT, CTRL, ALT, etc.). +The ``unicode`` attribute stores the 16-bit unicode value of the key that was pressed or released. +The ``scancode`` attribute represents the physical location of a key on the keyboard. + +The ``ACTIVEEVENT`` contains information about the application gaining or losing focus. The ``gain`` attribute +will be 1 if the mouse enters the window, otherwise ``gain`` will be 0. The ``state`` attribute will have a +value of ``SDL_APPMOUSEFOCUS`` if mouse focus was gained/lost, ``SDL_APPINPUTFOCUS`` if the application loses +or gains keyboard focus, or ``SDL_APPACTIVE`` if the application is minimized (``gain`` will be 0) or restored. + +| + +When compiled with SDL2, pygame has these additional events and their +attributes. + +:: + + AUDIODEVICEADDED which, iscapture (SDL backend >= 2.0.4) + AUDIODEVICEREMOVED which, iscapture (SDL backend >= 2.0.4) + FINGERMOTION touch_id, finger_id, x, y, dx, dy + FINGERDOWN touch_id, finger_id, x, y, dx, dy + FINGERUP touch_id, finger_id, x, y, dx, dy + MOUSEWHEEL which, flipped, x, y, touch, precise_x, precise_y + MULTIGESTURE touch_id, x, y, pinched, rotated, num_fingers + TEXTEDITING text, start, length + TEXTINPUT text + +.. versionadded:: 1.9.5 + +.. versionchanged:: 2.0.2 Fixed amount horizontal scroll (x, positive to the right and negative to the left). + +.. versionchanged:: 2.0.2 The ``touch`` attribute was added to all the ``MOUSE`` events. + +The ``touch`` attribute of ``MOUSE`` events indicates whether or not the events were generated +by a touch input device, and not a real mouse. You might want to ignore such events, if your application +already handles ``FINGERMOTION``, ``FINGERDOWN`` and ``FINGERUP`` events. + +.. versionadded:: 2.1.3 Added ``precise_x`` and ``precise_y`` to ``MOUSEWHEEL`` events + +``MOUSEWHEEL`` event occurs whenever the mouse wheel is moved. +The ``which`` attribute determines if the event was generated from a touch input device vs an actual +mousewheel. +The ``preciseX`` attribute contains a float with the amount scrolled horizontally (positive to the right, +negative to the left). +The ``preciseY`` attribute contains a float with the amount scrolled vertically (positive away from user, +negative towards user). +The ``flipped`` attribute determines if the values in x and y will be opposite or not. If ``SDL_MOUSEWHEEL_FLIPPED`` +is defined, the direction of x and y will be opposite. + +``TEXTEDITING`` event is triggered when a user activates an input method via hotkey or selecting an +input method in a GUI and starts typing + +The ``which`` attribute for ``AUDIODEVICE*`` events is an integer representing the index for new audio +devices that are added. ``AUDIODEVICE*`` events are used to update audio settings or device list. + +| + +Many new events were introduced in pygame 2. + +pygame can recognize text or files dropped in its window. If a file +is dropped, ``DROPFILE`` event will be sent, ``file`` will be its path. +The ``DROPTEXT`` event is only supported on X11. + +``MIDIIN`` and ``MIDIOUT`` are events reserved for :mod:`pygame.midi` use. +``MIDI*`` events differ from ``AUDIODEVICE*`` events in that AUDIODEVICE +events are triggered when there is a state change related to an audio +input/output device. + +pygame 2 also supports controller hot-plugging + +:: + + Event name Attributes and notes + + DROPFILE file + DROPBEGIN (SDL backend >= 2.0.5) + DROPCOMPLETE (SDL backend >= 2.0.5) + DROPTEXT text (SDL backend >= 2.0.5) + MIDIIN + MIDIOUT + CONTROLLERDEVICEADDED device_index + JOYDEVICEADDED device_index + CONTROLLERDEVICEREMOVED instance_id + JOYDEVICEREMOVED instance_id + CONTROLLERDEVICEREMAPPED instance_id + KEYMAPCHANGED (SDL backend >= 2.0.4) + CLIPBOARDUPDATE + RENDER_TARGETS_RESET (SDL backend >= 2.0.2) + RENDER_DEVICE_RESET (SDL backend >= 2.0.4) + LOCALECHANGED (SDL backend >= 2.0.14) + +Also in this version, ``instance_id`` attributes were added to joystick events, +and the ``joy`` attribute was deprecated. + +``KEYMAPCHANGED`` is a type of an event sent when keymap changes due to a +system event such as an input language or keyboard layout change. + +``CLIPBOARDUPDATE`` is an event sent when clipboard changes. This can still +be considered as an experimental feature, some kinds of clipboard changes might +not trigger this event. + +``LOCALECHANGED`` is an event sent when user locale changes + +.. versionadded:: 2.0.0 + +.. versionadded:: 2.1.3 ``KEYMAPCHANGED``, ``CLIPBOARDUPDATE``, + ``RENDER_TARGETS_RESET``, ``RENDER_DEVICE_RESET`` and ``LOCALECHANGED`` + +| + +Since pygame 2.0.1, there are a new set of events, called window events. +Here is a list of all window events, along with a short description + +:: + + Event type Short description + + WINDOWSHOWN Window became shown + WINDOWHIDDEN Window became hidden + WINDOWEXPOSED Window got updated by some external event + WINDOWMOVED Window got moved + WINDOWRESIZED Window got resized + WINDOWSIZECHANGED Window changed its size + WINDOWMINIMIZED Window was minimized + WINDOWMAXIMIZED Window was maximized + WINDOWRESTORED Window was restored + WINDOWENTER Mouse entered the window + WINDOWLEAVE Mouse left the window + WINDOWFOCUSGAINED Window gained focus + WINDOWFOCUSLOST Window lost focus + WINDOWCLOSE Window was closed + WINDOWTAKEFOCUS Window was offered focus (SDL backend >= 2.0.5) + WINDOWHITTEST Window has a special hit test (SDL backend >= 2.0.5) + WINDOWICCPROFCHANGED Window ICC profile changed (SDL backend >= 2.0.18) + WINDOWDISPLAYCHANGED Window moved on a new display (SDL backend >= 2.0.18) + + +``WINDOWMOVED``, ``WINDOWRESIZED`` and ``WINDOWSIZECHANGED`` have ``x`` and +``y`` attributes, ``WINDOWDISPLAYCHANGED`` has a ``display_index`` attribute. +All windowevents have a ``window`` attribute. + +.. versionadded:: 2.0.1 + +.. versionadded:: 2.1.3 ``WINDOWICCPROFCHANGED`` and ``WINDOWDISPLAYCHANGED`` + +| + +On Android, the following events can be generated + +:: + + Event type Short description + + APP_TERMINATING OS is terminating the application + APP_LOWMEMORY OS is low on memory, try to free memory if possible + APP_WILLENTERBACKGROUND Application is entering background + APP_DIDENTERBACKGROUND Application entered background + APP_WILLENTERFOREGROUND Application is entering foreground + APP_DIDENTERFOREGROUND Application entered foreground + +.. versionadded:: 2.1.3 + +| + +.. function:: pump + + | :sl:`internally process pygame event handlers` + | :sg:`pump() -> None` + + For each frame of your game, you will need to make some sort of call to the + event queue. This ensures your program can internally interact with the rest + of the operating system. If you are not using other event functions in your + game, you should call ``pygame.event.pump()`` to allow pygame to handle + internal actions. + + This function is not necessary if your program is consistently processing + events on the queue through the other :mod:`pygame.event` functions. + + There are important things that must be dealt with internally in the event + queue. The main window may need to be repainted or respond to the system. If + you fail to make a call to the event queue for too long, the system may + decide your program has locked up. + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.pump ## + +.. function:: get + + | :sl:`get events from the queue` + | :sg:`get(eventtype=None) -> Eventlist` + | :sg:`get(eventtype=None, pump=True) -> Eventlist` + | :sg:`get(eventtype=None, pump=True, exclude=None) -> Eventlist` + + This will get all the messages and remove them from the queue. If a type or + sequence of types is given only those messages will be removed from the + queue and returned. + + If a type or sequence of types is passed in the ``exclude`` argument + instead, then all only *other* messages will be removed from the queue. If + an ``exclude`` parameter is passed, the ``eventtype`` parameter *must* be + None. + + If you are only taking specific events from the queue, be aware that the + queue could eventually fill up with the events you are not interested. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + .. versionchanged:: 2.0.2 Added ``exclude`` argument + + .. ## pygame.event.get ## + +.. function:: poll + + | :sl:`get a single event from the queue` + | :sg:`poll() -> Event instance` + + Returns a single event from the queue. If the event queue is empty an event + of type ``pygame.NOEVENT`` will be returned immediately. The returned event + is removed from the queue. + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.poll ## + +.. function:: wait + + | :sl:`wait for a single event from the queue` + | :sg:`wait() -> Event instance` + | :sg:`wait(timeout) -> Event instance` + + Returns a single event from the queue. If the queue is empty this function + will wait until one is created. From pygame 2.0.0, if a ``timeout`` argument + is given, the function will return an event of type ``pygame.NOEVENT`` + if no events enter the queue in ``timeout`` milliseconds. The event is removed + from the queue once it has been returned. While the program is waiting it will + sleep in an idle state. This is important for programs that want to share the + system with other applications. + + .. versionchanged:: 2.0.0.dev13 Added ``timeout`` argument + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.wait ## + +.. function:: peek + + | :sl:`test if event types are waiting on the queue` + | :sg:`peek(eventtype=None) -> bool` + | :sg:`peek(eventtype=None, pump=True) -> bool` + + Returns ``True`` if there are any events of the given type waiting on the + queue. If a sequence of event types is passed, this will return ``True`` if + any of those events are on the queue. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + + .. ## pygame.event.peek ## + +.. function:: clear + + | :sl:`remove all events from the queue` + | :sg:`clear(eventtype=None) -> None` + | :sg:`clear(eventtype=None, pump=True) -> None` + + Removes all events from the queue. If ``eventtype`` is given, removes the given event + or sequence of events. This has the same effect as :func:`pygame.event.get()` except ``None`` + is returned. It can be slightly more efficient when clearing a full event queue. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + + .. ## pygame.event.clear ## + +.. function:: event_name + + | :sl:`get the string name from an event id` + | :sg:`event_name(type) -> string` + + Returns a string representing the name (in CapWords style) of the given + event type. + + "UserEvent" is returned for all values in the user event id range. + "Unknown" is returned when the event type does not exist. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + .. ## pygame.event.event_name ## + + +.. function:: set_blocked + + | :sl:`control which events are allowed on the queue` + | :sg:`set_blocked(type) -> None` + | :sg:`set_blocked(typelist) -> None` + | :sg:`set_blocked(None) -> None` + + The given event types are not allowed to appear on the event queue. By + default all events can be placed on the queue. It is safe to disable an + event type multiple times. + + If ``None`` is passed as the argument, ALL of the event types are blocked + from being placed on the queue. + + .. ## pygame.event.set_blocked ## + +.. function:: set_allowed + + | :sl:`control which events are allowed on the queue` + | :sg:`set_allowed(type) -> None` + | :sg:`set_allowed(typelist) -> None` + | :sg:`set_allowed(None) -> None` + + The given event types are allowed to appear on the event queue. By default, + all event types can be placed on the queue. It is safe to enable an event + type multiple times. + + If ``None`` is passed as the argument, ALL of the event types are allowed + to be placed on the queue. + + .. ## pygame.event.set_allowed ## + +.. function:: get_blocked + + | :sl:`test if a type of event is blocked from the queue` + | :sg:`get_blocked(type) -> bool` + | :sg:`get_blocked(typelist) -> bool` + + Returns ``True`` if the given event type is blocked from the queue. If a + sequence of event types is passed, this will return ``True`` if any of those + event types are blocked. + + .. ## pygame.event.get_blocked ## + +.. function:: set_grab + + | :sl:`control the sharing of input devices with other applications` + | :sg:`set_grab(bool) -> None` + + When your program runs in a windowed environment, it will share the mouse + and keyboard devices with other applications that have focus. If your + program sets the event grab to ``True``, it will lock all input into your + program. + + It is best to not always grab the input, since it prevents the user from + doing other things on their system. + + .. ## pygame.event.set_grab ## + +.. function:: get_grab + + | :sl:`test if the program is sharing input devices` + | :sg:`get_grab() -> bool` + + Returns ``True`` when the input events are grabbed for this application. + + .. ## pygame.event.get_grab ## + +.. function:: set_keyboard_grab + + | :sl:`grab enables capture of system keyboard shortcuts like Alt+Tab or the Meta/Super key.` + | :sg:`set_keyboard_grab(bool) -> None` + + Keyboard grab enables capture of system keyboard shortcuts like Alt+Tab or the Meta/Super key. + Note that not all system keyboard shortcuts can be captured by applications (one example is Ctrl+Alt+Del on Windows). + This is primarily intended for specialized applications such as VNC clients or VM frontends. Normal games should not use keyboard grab. + + .. versionadded:: 2.5.0 + + .. ## pygame.event.set_keyboard_grab ## + +.. function:: get_keyboard_grab + + | :sl:`get the current keyboard grab state` + | :sg:`get_keyboard_grab() -> bool` + + Returns ``True`` when keyboard grab is enabled. + + .. versionadded:: 2.5.0 + + .. ## pygame.event.get_keyboard_grab ## + +.. function:: post + + | :sl:`place a new event on the queue` + | :sg:`post(Event) -> bool` + + Places the given event at the end of the event queue. + + This is usually used for placing custom events on the event queue. + Any type of event can be posted, and the events posted can have any attributes. + + This returns a boolean on whether the event was posted or not. Blocked events + cannot be posted, and this function returns ``False`` if you try to post them. + + .. versionchanged:: 2.0.1 returns a boolean, previously returned ``None`` + + .. ## pygame.event.post ## + +.. function:: custom_type + + | :sl:`make custom user event type` + | :sg:`custom_type() -> int` + + Reserves a ``pygame.USEREVENT`` for a custom use. + + If too many events are made a :exc:`pygame.error` is raised. + + .. versionadded:: 2.0.0.dev3 + + .. ## pygame.event.custom_type ## + +.. class:: Event + + | :sl:`pygame object for representing events` + | :sg:`Event(type, dict) -> Event` + | :sg:`Event(type, \**attributes) -> Event` + + A pygame object used for representing an event. ``Event`` instances + support attribute assignment and deletion. + + When creating the object, the attributes may come from a dictionary + argument with string keys or from keyword arguments. + + .. note:: + From version 2.1.3 ``EventType`` is an alias for ``Event``. Beforehand, + ``Event`` was a function that returned ``EventType`` instances. Use of + ``Event`` is preferred over ``EventType`` wherever it is possible, as + the latter could be deprecated in a future version. + + .. attribute:: type + + | :sl:`event type identifier.` + | :sg:`type -> int` + + Read-only. The event type identifier. For user created event + objects, this is the ``type`` argument passed to + :func:`pygame.event.Event()`. + + For example, some predefined event identifiers are ``QUIT`` and + ``MOUSEMOTION``. + + .. ## pygame.event.Event.type ## + + .. attribute:: __dict__ + + | :sl:`event attribute dictionary` + | :sg:`__dict__ -> dict` + + Read-only. The event type specific attributes of an event. The + ``dict`` attribute is a synonym for backward compatibility. + + For example, the attributes of a ``KEYDOWN`` event would be ``unicode``, + ``key``, and ``mod`` + + .. ## pygame.event.Event.__dict__ ## + + .. versionadded:: 1.9.2 Mutable attributes. + + .. ## pygame.event.Event ## + +.. ## pygame.event ## diff --git a/docs/ref/examples.rst b/docs/ref/examples.rst new file mode 100644 index 0000000..000ea76 --- /dev/null +++ b/docs/ref/examples.rst @@ -0,0 +1,451 @@ +.. include:: common.txt + +:mod:`pygame.examples` +====================== + +.. module:: pygame.examples + :synopsis: module of example programs + +| :sl:`module of example programs` + +These examples should help get you started with pygame. Here is a brief rundown +of what you get. The source code for these examples is in the public domain. +Feel free to use for your own projects. + +There are several ways to run the examples. First they can be run as +stand-alone programs. Second they can be imported and their ``main()`` methods +called (see below). Finally, the easiest way is to use the python -m option: + +:: + + python -m pygame.examples. + +eg: + +:: + + python -m pygame.examples.scaletest someimage.png + +Resources such as images and sounds for the examples are found in the +pygame/examples/data subdirectory. + +You can find where the example files are installed by using the following +commands inside the python interpreter. + +:: + + >>> import pygame.examples.scaletest + >>> pygame.examples.scaletest.__file__ + '/usr/lib/python2.6/site-packages/pygame/examples/scaletest.py' + +On each OS and version of Python the location will be slightly different. +For example on Windows it might be in 'C:/Python26/Lib/site-packages/pygame/examples/' +On Mac OS X it might be in '/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/pygame/examples/' + + +You can also run the examples in the python interpreter by calling each modules main() function. + +:: + + >>> import pygame.examples.scaletest + >>> pygame.examples.scaletest.main() + + +We're always on the lookout for more examples and/or example requests. Code +like this is probably the best way to start getting involved with python +gaming. + +examples as a package is new to pygame 1.9.0. But most of the examples came with +pygame much earlier. + +.. function:: aliens.main + + | :sl:`play the full aliens example` + | :sg:`aliens.main() -> None` + + This started off as a port of the ``SDL`` demonstration, Aliens. Now it has + evolved into something sort of resembling fun. This demonstrates a lot of + different uses of sprites and optimized blitting. Also transparency, + colorkeys, fonts, sound, music, joystick, and more. (PS, my high score is + 117! goodluck) + + .. ## pygame.examples.aliens.main ## + +.. function:: stars.main + + | :sl:`run a simple starfield example` + | :sg:`stars.main() -> None` + + A simple starfield example. You can change the center of perspective by + leftclicking the mouse on the screen. + + .. ## pygame.examples.stars.main ## + +.. function:: chimp.main + + | :sl:`hit the moving chimp` + | :sg:`chimp.main() -> None` + + This simple example is derived from the line-by-line tutorial that comes + with pygame. It is based on a 'popular' web banner. Note there are comments + here, but for the full explanation, follow along in the tutorial. + + .. ## pygame.examples.chimp.main ## + +.. function:: moveit.main + + | :sl:`display animated objects on the screen` + | :sg:`moveit.main() -> None` + + This is the full and final example from the Pygame Tutorial, "How Do I Make + It Move". It creates 10 objects and animates them on the screen. + + Note it's a bit scant on error checking, but it's easy to read. :] + Fortunately, this is python, and we needn't wrestle with a pile of error + codes. + + .. ## pygame.examples.moveit.main ## + +.. function:: fonty.main + + | :sl:`run a font rendering example` + | :sg:`fonty.main() -> None` + + Super quick, super simple application demonstrating the different ways to + render fonts with the font module + + .. ## pygame.examples.fonty.main ## + +.. function:: freetype_misc.main + + | :sl:`run a FreeType rendering example` + | :sg:`freetype_misc.main() -> None` + + A showcase of rendering features the :class:`pygame.freetype.Font` + class provides in addition to those available with :class:`pygame.font.Font`. + It is a demonstration of direct to surface rendering, with vertical text + and rotated text, opaque text and semi transparent text, horizontally + stretched text and vertically stretched text. + + .. ## pygame.examples.fonty.main ## + +.. function:: vgrade.main + + | :sl:`display a vertical gradient` + | :sg:`vgrade.main() -> None` + + Demonstrates creating a vertical gradient with pixelcopy and NumPy python. + The app will create a new gradient every half second and report the time + needed to create and display the image. If you're not prepared to start + working with the NumPy arrays, don't worry about the source for this one :] + + .. ## pygame.examples.vgrade.main ## + +.. function:: eventlist.main + + | :sl:`display pygame events` + | :sg:`eventlist.main() -> None` + + Eventlist is a sloppy style of pygame, but is a handy tool for learning + about pygame events and input. At the top of the screen are the state of + several device values, and a scrolling list of events are displayed on the + bottom. + + This is not quality 'ui' code at all, but you can see how to implement very + non-interactive status displays, or even a crude text output control. + + .. ## pygame.examples.eventlist.main ## + +.. function:: arraydemo.main + + | :sl:`show various surfarray effects` + | :sg:`arraydemo.main(arraytype=None) -> None` + + Another example filled with various surfarray effects. It requires the + surfarray and image modules to be installed. This little demo can also make + a good starting point for any of your own tests with surfarray + + The ``arraytype`` parameter is deprecated; passing any value besides 'numpy' + will raise ValueError. + + .. ## pygame.examples.arraydemo.main ## + +.. function:: sound.main + + | :sl:`load and play a sound` + | :sg:`sound.main(file_path=None) -> None` + + Extremely basic testing of the mixer module. Load a sound and play it. All + from the command shell, no graphics. + + If provided, use the audio file 'file_path', otherwise use a default file. + + ``sound.py`` optional command line argument: an audio file + + .. ## pygame.examples.sound.main ## + +.. function:: sound_array_demos.main + + | :sl:`play various sndarray effects` + | :sg:`sound_array_demos.main(arraytype=None) -> None` + + + Uses sndarray and NumPy to create offset faded copies of the + original sound. Currently it just uses hardcoded values for the number of + echoes and the delay. Easy for you to recreate as needed. + + The ``arraytype`` parameter is deprecated; passing any value besides 'numpy' + will raise ValueError. + + .. ## pygame.examples.sound_array_demos.main ## + +.. function:: liquid.main + + | :sl:`display an animated liquid effect` + | :sg:`liquid.main() -> None` + + This example was created in a quick comparison with the BlitzBasic gaming + language. Nonetheless, it demonstrates a quick 8-bit setup (with colormap). + + .. ## pygame.examples.liquid.main ## + +.. function:: glcube.main + + | :sl:`display an animated 3D cube using OpenGL` + | :sg:`glcube.main() -> None` + + Using PyOpenGL and pygame, this creates a spinning 3D multicolored cube. + + .. ## pygame.examples.glcube.main ## + +.. function:: scrap_clipboard.main + + | :sl:`access the clipboard` + | :sg:`scrap_clipboard.main() -> None` + + A simple demonstration example for the clipboard support. + + .. ## pygame.examples.scrap_clipboard.main ## + +.. function:: mask.main + + | :sl:`display multiple images bounce off each other using collision detection` + | :sg:`mask.main(*args) -> None` + + Positional arguments: + + :: + + one or more image file names. + + This ``pygame.masks`` demo will display multiple moving sprites bouncing off + each other. More than one sprite image can be provided. + + If run as a program then ``mask.py`` takes one or more image files as + command line arguments. + + .. ## pygame.examples.mask.main ## + +.. function:: testsprite.main + + | :sl:`show lots of sprites moving around` + | :sg:`testsprite.main(update_rects = True, use_static = False, use_FastRenderGroup = False, screen_dims = [640, 480], use_alpha = False, flags = 0) -> None` + + Optional keyword arguments: + + :: + + update_rects - use the RenderUpdate sprite group class + use_static - include non-moving images + use_FastRenderGroup - Use the FastRenderGroup sprite group + screen_dims - pygame window dimensions + use_alpha - use alpha blending + flags - additional display mode flags + + Like the ``testsprite.c`` that comes with SDL, this pygame version shows + lots of sprites moving around. + + If run as a stand-alone program then no command line arguments are taken. + + .. ## pygame.examples.testsprite.main ## + +.. function:: headless_no_windows_needed.main + + | :sl:`write an image file that is smoothscaled copy of an input file` + | :sg:`headless_no_windows_needed.main(fin, fout, w, h) -> None` + + arguments: + + :: + + fin - name of an input image file + fout - name of the output file to create/overwrite + w, h - size of the rescaled image, as integer width and height + + How to use pygame with no windowing system, like on headless servers. + + Thumbnail generation with scaling is an example of what you can do with + pygame. + + ``NOTE``: the pygame scale function uses MMX/SSE if available, and can be + run in multiple threads. + + If ``headless_no_windows_needed.py`` is run as a program it takes the + following command line arguments: + + :: + + -scale inputimage outputimage new_width new_height + eg. -scale in.png outpng 50 50 + + .. ## pygame.examples.headless_no_windows_needed.main ## + +.. function:: joystick.main + + | :sl:`demonstrate joystick functionality` + | :sg:`joystick.main() -> None` + + A demo showing full joystick support. + + .. versionadded:: 2.0.2 + + .. ## pygame.examples.joystick.main ## + +.. function:: blend_fill.main + + | :sl:`demonstrate the various surface.fill method blend options` + | :sg:`blend_fill.main() -> None` + + A interactive demo that lets one choose which BLEND_xxx option to apply to a + surface. + + .. ## pygame.examples.blend_fill.main ## + +.. function:: blit_blends.main + + | :sl:`uses alternative additive fill to that of surface.fill` + | :sg:`blit_blends.main() -> None` + + Fake additive blending. Using NumPy. it doesn't clamp. Press r,g,b Somewhat + like blend_fill. + + .. ## pygame.examples.blit_blends.main ## + +.. function:: cursors.main + + | :sl:`display two different custom cursors` + | :sg:`cursors.main() -> None` + + Display an arrow or circle with crossbar cursor. + + .. ## pygame.examples.cursors.main ## + +.. function:: pixelarray.main + + | :sl:`display various pixelarray generated effects` + | :sg:`pixelarray.main() -> None` + + Display various pixelarray generated effects. + + .. ## pygame.examples.pixelarray.main ## + +.. function:: scaletest.main + + | :sl:`interactively scale an image using smoothscale` + | :sg:`scaletest.main(imagefile, convert_alpha=False, run_speed_test=True) -> None` + + arguments: + + :: + + imagefile - file name of source image (required) + convert_alpha - use convert_alpha() on the surf (default False) + run_speed_test - (default False) + + A smoothscale example that resized an image on the screen. Vertical and + horizontal arrow keys are used to change the width and height of the + displayed image. If the convert_alpha option is True then the source image + is forced to have source alpha, whether or not the original images does. If + run_speed_test is True then a background timing test is performed instead of + the interactive scaler. + + If ``scaletest.py`` is run as a program then the command line options are: + + :: + + ImageFile [-t] [-convert_alpha] + [-t] = Run Speed Test + [-convert_alpha] = Use convert_alpha() on the surf. + + .. ## pygame.examples.scaletest.main ## + +.. function:: midi.main + + | :sl:`run a midi example` + | :sg:`midi.main(mode='output', device_id=None) -> None` + + Arguments: + + :: + + mode - if 'output' run a midi keyboard output example + 'input' run a midi event logger input example + 'list' list available midi devices + (default 'output') + device_id - midi device number; if None then use the default midi input or + output device for the system + + The output example shows how to translate mouse clicks or computer keyboard + events into midi notes. It implements a rudimentary button widget and state + machine. + + The input example shows how to translate midi input to pygame events. + + With the use of a virtual midi patch cord the output and input examples can + be run as separate processes and connected so the keyboard output is + displayed on a console. + + new to pygame 1.9.0 + + .. ## pygame.examples.midi.main ## + +.. function:: scroll.main + + | :sl:`run a Surface.scroll example that shows a magnified image` + | :sg:`scroll.main(image_file=None) -> None` + + This example shows a scrollable image that has a zoom factor of eight. It + uses the :meth:`Surface.scroll() ` + function to shift the image on the display surface. + A clip rectangle protects a margin area. If called as a function, + the example accepts an optional image file path. If run as a program it + takes an optional file path command line argument. If no file is provided a + default image file is used. + + When running click on a black triangle to move one pixel in the direction + the triangle points. Or use the arrow keys. Close the window or press + ``ESC`` to quit. + + .. ## pygame.examples.scroll.main ## + +.. function:: camera.main + + | :sl:`display video captured live from an attached camera` + | :sg:`camera.main() -> None` + + A simple live video player, it uses the first available camera it finds on + the system. + + .. ## pygame.examples.camera.main ## + +.. function:: playmus.main + + | :sl:`play an audio file` + | :sg:`playmus.main(file_path) -> None` + + A simple music player with window and keyboard playback control. Playback can + be paused and rewound to the beginning. + + .. ## pygame.examples.playmus.main ## + +.. ## pygame.examples ## diff --git a/docs/ref/fastevent.rst b/docs/ref/fastevent.rst new file mode 100644 index 0000000..a2efe5f --- /dev/null +++ b/docs/ref/fastevent.rst @@ -0,0 +1,109 @@ +.. include:: common.txt + +:mod:`pygame.fastevent` +======================= + +.. module:: pygame.fastevent + :synopsis: pygame module for interacting with events and queues from multiple + threads. + +| :sl:`pygame module for interacting with events and queues` + +IMPORTANT NOTE: THIS MODULE IS DEPRECATED IN PYGAME 2.2 + +In older pygame versions before pygame 2, :mod:`pygame.event` was not well +suited for posting events from different threads. This module served as a +replacement (with less features) for multithreaded use. Now, the usage of this +module is highly discouraged in favour of use of the main :mod:`pygame.event` +module. This module will be removed in a future pygame version. + +Below, the legacy docs of the module is provided + +.. function:: init + + | :sl:`initialize pygame.fastevent` + | :sg:`init() -> None` + + Initialize the pygame.fastevent module. + + .. ## pygame.fastevent.init ## + +.. function:: get_init + + | :sl:`returns True if the fastevent module is currently initialized` + | :sg:`get_init() -> bool` + + Returns True if the pygame.fastevent module is currently initialized. + + .. ## pygame.fastevent.get_init ## + +.. function:: pump + + | :sl:`internally process pygame event handlers` + | :sg:`pump() -> None` + + For each frame of your game, you will need to make some sort of call to the + event queue. This ensures your program can internally interact with the rest + of the operating system. + + This function is not necessary if your program is consistently processing + events on the queue through the other :mod:`pygame.fastevent` functions. + + There are important things that must be dealt with internally in the event + queue. The main window may need to be repainted or respond to the system. If + you fail to make a call to the event queue for too long, the system may + decide your program has locked up. + + .. ## pygame.fastevent.pump ## + +.. function:: wait + + | :sl:`wait for an event` + | :sg:`wait() -> Event` + + Returns the current event on the queue. If there are no messages + waiting on the queue, this will not return until one is available. + Sometimes it is important to use this wait to get events from the queue, + it will allow your application to idle when the user isn't doing anything + with it. + + .. ## pygame.fastevent.wait ## + +.. function:: poll + + | :sl:`get an available event` + | :sg:`poll() -> Event` + + Returns next event on queue. If there is no event waiting on the queue, + this will return an event with type NOEVENT. + + .. ## pygame.fastevent.poll ## + +.. function:: get + + | :sl:`get all events from the queue` + | :sg:`get() -> list of Events` + + This will get all the messages and remove them from the queue. + + .. ## pygame.fastevent.get ## + +.. function:: post + + | :sl:`place an event on the queue` + | :sg:`post(Event) -> None` + + This will post your own event objects onto the event queue. You can post + any event type you want, but some care must be taken. For example, if you + post a MOUSEBUTTONDOWN event to the queue, it is likely any code receiving + the event will expect the standard MOUSEBUTTONDOWN attributes to be + available, like 'pos' and 'button'. + + Because pygame.fastevent.post() may have to wait for the queue to empty, + you can get into a dead lock if you try to append an event on to a full + queue from the thread that processes events. For that reason I do not + recommend using this function in the main thread of an SDL program. + + .. ## pygame.fastevent.post ## + +.. ## pygame.fastevent ## \ No newline at end of file diff --git a/docs/ref/font.rst b/docs/ref/font.rst new file mode 100644 index 0000000..9f09a8b --- /dev/null +++ b/docs/ref/font.rst @@ -0,0 +1,499 @@ +.. include:: common.txt + +:mod:`pygame.font` +================== + +.. module:: pygame.font + :synopsis: pygame module for loading and rendering fonts + +| :sl:`pygame module for loading and rendering fonts` + +The font module allows for rendering TrueType fonts into Surface objects. +This module is built on top of the SDL_ttf library, which comes with all +normal pygame installations. + +Most of the work done with fonts are done by using the actual Font objects. +The module by itself only has routines to support the creation of Font objects +with :func:`pygame.font.Font`. + +You can load fonts from the system by using the :func:`pygame.font.SysFont` +function. There are a few other functions to help look up the system fonts. + +Pygame comes with a builtin default font, freesansbold. This can always be +accessed by passing ``None`` as the font name. + +Before pygame 2.0.3, pygame.font accepts any UCS-2 / UTF-16 character +('\\u0001' to '\\uFFFF'). After 2.0.3, pygame.font built with SDL_ttf +2.0.15 accepts any valid UCS-4 / UTF-32 character +(like emojis, if the font has them) ('\\U00000001' to '\\U0010FFFF')). +More about this in :func:`Font.render`. + +Before pygame 2.0.3, this character space restriction can be avoided by +using the :mod:`pygame.freetype` based ``pygame.ftfont`` to emulate the Font +module. This can be used by defining the environment variable PYGAME_FREETYPE +before the first import of :mod:`pygame`. Since the problem ``pygame.ftfont`` +solves no longer exists, it will likely be removed in the future. + +.. function:: init + + | :sl:`initialize the font module` + | :sg:`init() -> None` + + This method is called automatically by ``pygame.init()``. It initializes the + font module. The module must be initialized before any other functions will + work. + + It is safe to call this function more than once. + + .. ## pygame.font.init ## + +.. function:: quit + + | :sl:`uninitialize the font module` + | :sg:`quit() -> None` + + Manually uninitialize SDL_ttf's font system. This is called automatically by + ``pygame.quit()``. + + It is safe to call this function even if font is currently not initialized. + + .. ## pygame.font.quit ## + +.. function:: get_init + + | :sl:`true if the font module is initialized` + | :sg:`get_init() -> bool` + + Test if the font module is initialized or not. + + .. ## pygame.font.get_init ## + +.. function:: get_default_font + + | :sl:`get the filename of the default font` + | :sg:`get_default_font() -> string` + + Return the filename of the system font. This is not the full path to the + file. This file can usually be found in the same directory as the font + module, but it can also be bundled in separate archives. + + .. ## pygame.font.get_default_font ## + +.. function:: get_sdl_ttf_version + + | :sl:`gets SDL_ttf version` + | :sg:`get_sdl_ttf_version(linked=True) -> (major, minor, patch)` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave get_sdl_ttf_version feedback with authors `_ + + Returns a tuple of integers that identify SDL_ttf's version. + SDL_ttf is the underlying font rendering library, written in C, + on which pygame's font module depends. If 'linked' is True (the default), + the function returns the version of the linked TTF library. + Otherwise this function returns the version of TTF pygame was compiled with + + .. versionadded:: 2.1.3 + + .. ## pygame.font.get_sdl_ttf_version ## + +.. function:: get_fonts + + | :sl:`get all available fonts` + | :sg:`get_fonts() -> list of strings` + + Returns a list of all the fonts available on the system. The names of the + fonts will be set to lowercase with all spaces and punctuation removed. This + works on most systems, but some will return an empty list if they cannot + find fonts. + + .. versionchanged:: 2.1.3 Checks through user fonts instead of just global fonts for Windows. + + .. ## pygame.font.get_fonts ## + +.. function:: match_font + + | :sl:`find a specific font on the system` + | :sg:`match_font(name, bold=False, italic=False) -> path` + + Returns the full path to a font file on the system. If bold or italic are + set to true, this will attempt to find the correct family of font. + + The font name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + If none of the given names are found, None is returned. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + + .. versionchanged:: 2.1.3 Checks through user fonts instead of just global fonts for Windows. + + Example: + + :: + + print pygame.font.match_font('bitstreamverasans') + # output is: /usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf + # (but only if you have Vera on your system) + + .. ## pygame.font.match_font ## + +.. function:: SysFont + + | :sl:`create a Font object from the system fonts` + | :sg:`SysFont(name, size, bold=False, italic=False) -> Font` + + Return a new Font object that is loaded from the system fonts. The font will + match the requested bold and italic flags. Pygame uses a small set of common + font aliases. If the specific font you ask for is not available, a reasonable + alternative may be used. If a suitable system font is not found this will + fall back on loading the default pygame font. + + The font name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + + .. versionchanged:: 2.1.3 Checks through user fonts instead of just global fonts for Windows. + + .. ## pygame.font.SysFont ## + +.. class:: Font + + | :sl:`create a new Font object from a file` + | :sg:`Font(file_path=None, size=12) -> Font` + | :sg:`Font(file_path, size) -> Font` + | :sg:`Font(pathlib.Path, size) -> Font` + | :sg:`Font(object, size) -> Font` + + Load a new font from a given filename or a python file object. The size is + the height of the font in pixels. If the filename is ``None`` the pygame + default font will be loaded. If a font cannot be loaded from the arguments + given an exception will be raised. Once the font is created the size cannot + be changed. If no arguments are given then the default font will be used and + a font size of 12 is used. + + Font objects are mainly used to render text into new Surface objects. The + render can emulate bold or italic features, but it is better to load from a + font with actual italic or bold glyphs. + + .. attribute:: bold + + | :sl:`Gets or sets whether the font should be rendered in (faked) bold.` + | :sg:`bold -> bool` + + Whether the font should be rendered in bold. + + When set to True, this enables the bold rendering of text. This + is a fake stretching of the font that doesn't look good on many + font types. If possible load the font from a real bold font + file. While bold, the font will have a different width than when + normal. This can be mixed with the italic, underline and + strikethrough modes. + + .. versionadded:: 2.0.0 + + .. ## Font.bold ## + + .. attribute:: italic + + | :sl:`Gets or sets whether the font should be rendered in (faked) italics.` + | :sg:`italic -> bool` + + Whether the font should be rendered in italic. + + When set to True, this enables fake rendering of italic + text. This is a fake skewing of the font that doesn't look good + on many font types. If possible load the font from a real italic + font file. While italic the font will have a different width + than when normal. This can be mixed with the bold, underline and + strikethrough modes. + + .. versionadded:: 2.0.0 + + .. ## Font.italic ## + + .. attribute:: underline + + | :sl:`Gets or sets whether the font should be rendered with an underline.` + | :sg:`underline -> bool` + + Whether the font should be rendered in underline. + + When set to True, all rendered fonts will include an + underline. The underline is always one pixel thick, regardless + of font size. This can be mixed with the bold, italic and + strikethrough modes. + + .. versionadded:: 2.0.0 + + .. ## Font.underline ## + + .. attribute:: strikethrough + + | :sl:`Gets or sets whether the font should be rendered with a strikethrough.` + | :sg:`strikethrough -> bool` + + Whether the font should be rendered with a strikethrough. + + When set to True, all rendered fonts will include an + strikethrough. The strikethrough is always one pixel thick, + regardless of font size. This can be mixed with the bold, + italic and underline modes. + + .. versionadded:: 2.1.3 + + .. ## Font.strikethrough ## + + .. method:: render + + | :sl:`draw text on a new Surface` + | :sg:`render(text, antialias, color, background=None) -> Surface` + + This creates a new Surface with the specified text rendered on it. + :mod:`pygame.font` provides no way to directly draw text on an existing + Surface: instead you must use :func:`Font.render` to create an image + (Surface) of the text, then blit this image onto another Surface. + + The text can only be a single line: newline characters are not rendered. + Null characters ('\x00') raise a TypeError. Both Unicode and char (byte) + strings are accepted. For Unicode strings only UCS-2 characters + ('\\u0001' to '\\uFFFF') were previously supported and any greater + unicode codepoint would raise a UnicodeError. Now, characters in the + UCS-4 range are supported. For char strings a ``LATIN1`` encoding is + assumed. The antialias argument is a boolean: if True the characters + will have smooth edges. The color argument is the color of the text + [e.g.: (0,0,255) for blue]. The optional background argument is a color + to use for the text background. If no background is passed the area + outside the text will be transparent. + + The Surface returned will be of the dimensions required to hold the text. + (the same as those returned by :func:`Font.size`). If an empty string is passed + for the text, a blank surface will be returned that is zero pixel wide and + the height of the font. + + Depending on the type of background and antialiasing used, this returns + different types of Surfaces. For performance reasons, it is good to know + what type of image will be used. If antialiasing is not used, the return + image will always be an 8-bit image with a two-color palette. If the + background is transparent a colorkey will be set. Antialiased images are + rendered to 24-bit ``RGB`` images. If the background is transparent a + pixel alpha will be included. + + Optimization: if you know that the final destination for the text (on the + screen) will always have a solid background, and the text is antialiased, + you can improve performance by specifying the background color. This will + cause the resulting image to maintain transparency information by + colorkey rather than (much less efficient) alpha values. + + If you render '\\n' an unknown char will be rendered. Usually a + rectangle. Instead you need to handle newlines yourself. + + Font rendering is not thread safe: only a single thread can render text + at any time. + + .. versionchanged:: 2.0.3 Rendering UCS4 unicode works and does not + raise an exception. Use `if hasattr(pygame.font, "UCS4"):` to see if + pygame supports rendering UCS4 unicode including more languages and + emoji. + + .. ## Font.render ## + + .. method:: size + + | :sl:`determine the amount of space needed to render text` + | :sg:`size(text) -> (width, height)` + + Returns the dimensions needed to render the text. This can be used to + help determine the positioning needed for text before it is rendered. It + can also be used for word wrapping and other layout effects. + + Be aware that most fonts use kerning which adjusts the widths for + specific letter pairs. For example, the width for "ae" will not always + match the width for "a" + "e". + + .. ## Font.size ## + + .. method:: set_underline + + | :sl:`control if text is rendered with an underline` + | :sg:`set_underline(bool) -> None` + + When enabled, all rendered fonts will include an underline. The underline + is always one pixel thick, regardless of font size. This can be mixed + with the bold, italic and strikethrough modes. + + .. note:: This is the same as the :attr:`underline` attribute. + + .. ## Font.set_underline ## + + .. method:: get_underline + + | :sl:`check if text will be rendered with an underline` + | :sg:`get_underline() -> bool` + + Return True when the font underline is enabled. + + .. note:: This is the same as the :attr:`underline` attribute. + + .. ## Font.get_underline ## + + .. method:: set_strikethrough + + | :sl:`control if text is rendered with a strikethrough` + | :sg:`set_strikethrough(bool) -> None` + + When enabled, all rendered fonts will include a strikethrough. The + strikethrough is always one pixel thick, regardless of font size. + This can be mixed with the bold, italic and underline modes. + + .. note:: This is the same as the :attr:`strikethrough` attribute. + + .. versionadded:: 2.1.3 + + .. ## Font.set_strikethrough ## + + .. method:: get_strikethrough + + | :sl:`check if text will be rendered with a strikethrough` + | :sg:`get_strikethrough() -> bool` + + Return True when the font strikethrough is enabled. + + .. note:: This is the same as the :attr:`strikethrough` attribute. + + .. versionadded:: 2.1.3 + + .. ## Font.get_strikethrough ## + + .. method:: set_bold + + | :sl:`enable fake rendering of bold text` + | :sg:`set_bold(bool) -> None` + + Enables the bold rendering of text. This is a fake stretching of the font + that doesn't look good on many font types. If possible load the font from + a real bold font file. While bold, the font will have a different width + than when normal. This can be mixed with the italic, underline and + strikethrough modes. + + .. note:: This is the same as the :attr:`bold` attribute. + + .. ## Font.set_bold ## + + .. method:: get_bold + + | :sl:`check if text will be rendered bold` + | :sg:`get_bold() -> bool` + + Return True when the font bold rendering mode is enabled. + + .. note:: This is the same as the :attr:`bold` attribute. + + .. ## Font.get_bold ## + + .. method:: set_italic + + | :sl:`enable fake rendering of italic text` + | :sg:`set_italic(bool) -> None` + + Enables fake rendering of italic text. This is a fake skewing of the font + that doesn't look good on many font types. If possible load the font from + a real italic font file. While italic the font will have a different + width than when normal. This can be mixed with the bold, underline and + strikethrough modes. + + .. note:: This is the same as the :attr:`italic` attribute. + + .. ## Font.set_italic ## + + .. method:: metrics + + | :sl:`gets the metrics for each character in the passed string` + | :sg:`metrics(text) -> list` + + The list contains tuples for each character, which contain the minimum + ``X`` offset, the maximum ``X`` offset, the minimum ``Y`` offset, the + maximum ``Y`` offset and the advance offset (bearing plus width) of the + character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny, maxy, + advance), ...]. None is entered in the list for each unrecognized + character. + + .. ## Font.metrics ## + + .. method:: get_italic + + | :sl:`check if the text will be rendered italic` + | :sg:`get_italic() -> bool` + + Return True when the font italic rendering mode is enabled. + + .. note:: This is the same as the :attr:`italic` attribute. + + .. ## Font.get_italic ## + + .. method:: get_linesize + + | :sl:`get the line space of the font text` + | :sg:`get_linesize() -> int` + + Return the height in pixels for a line of text with the font. When + rendering multiple lines of text this is the recommended amount of space + between lines. + + .. ## Font.get_linesize ## + + .. method:: get_height + + | :sl:`get the height of the font` + | :sg:`get_height() -> int` + + Return the height in pixels of the actual rendered text. This is the + average size for each glyph in the font. + + .. ## Font.get_height ## + + .. method:: get_ascent + + | :sl:`get the ascent of the font` + | :sg:`get_ascent() -> int` + + Return the height in pixels for the font ascent. The ascent is the number + of pixels from the font baseline to the top of the font. + + .. ## Font.get_ascent ## + + .. method:: get_descent + + | :sl:`get the descent of the font` + | :sg:`get_descent() -> int` + + Return the height in pixels for the font descent. The descent is the + number of pixels from the font baseline to the bottom of the font. + + .. ## Font.get_descent ## + + .. method:: set_script + + | :sl:`set the script code for text shaping` + | :sg:`set_script(str) -> None` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave feedback with authors `_ + + Sets the script used by harfbuzz text shaping, taking a 4 character + script code as input. For example, Hindi is written in the Devanagari + script, for which the script code is `"Deva"`. See the full list of + script codes in `ISO 15924 `_. + + This method requires pygame built with SDL_ttf 2.20.0 or above. Otherwise the + method will raise a pygame.error. + + .. versionadded:: 2.2.0 + + .. ## Font.set_script ## + + .. ## pygame.font.Font ## + +.. ## pygame.font ## diff --git a/docs/ref/freetype.rst b/docs/ref/freetype.rst new file mode 100644 index 0000000..0f282ac --- /dev/null +++ b/docs/ref/freetype.rst @@ -0,0 +1,770 @@ +.. include:: common.txt + +:mod:`pygame.freetype` +====================== + +.. module:: pygame.freetype + :synopsis: Enhanced pygame module for loading and rendering computer fonts + +| :sl:`Enhanced pygame module for loading and rendering computer fonts` + +The ``pygame.freetype`` module is a replacement for :mod:`pygame.font`. +It has all of the functionality of the original, plus many new features. +Yet is has absolutely no dependencies on the SDL_ttf library. +It is implemented directly on the FreeType 2 library. +The ``pygame.freetype`` module is not itself backward compatible with +:mod:`pygame.font`. +Instead, use the ``pygame.ftfont`` module as a drop-in replacement +for :mod:`pygame.font`. + +All font file formats supported by FreeType can be rendered by +``pygame.freetype``, namely ``TTF``, Type1, ``CFF``, OpenType, +``SFNT``, ``PCF``, ``FNT``, ``BDF``, ``PFR`` and Type42 fonts. +All glyphs having UTF-32 code points are accessible +(see :attr:`Font.ucs4`). + +Most work on fonts is done using :class:`Font` instances. +The module itself only has routines for initialization and creation +of :class:`Font` objects. +You can load fonts from the system using the :func:`SysFont` function. + +Extra support of bitmap fonts is available. Available bitmap sizes can +be listed (see :meth:`Font.get_sizes`). For bitmap only fonts :class:`Font` +can set the size for you (see the :attr:`Font.size` property). + +For now undefined character codes are replaced with the ``.notdef`` +(not defined) character. +How undefined codes are handled may become configurable in a future release. + +Pygame comes with a built-in default font. This can always be accessed by +passing None as the font name to the :class:`Font` constructor. + +Extra rendering features available to :class:`pygame.freetype.Font` +are direct to surface rendering (see :meth:`Font.render_to`), character kerning +(see :attr:`Font.kerning`), vertical layout (see :attr:`Font.vertical`), +rotation of rendered text (see :attr:`Font.rotation`), +and the strong style (see :attr:`Font.strong`). +Some properties are configurable, such as +strong style strength (see :attr:`Font.strength`) and underline positioning +(see :attr:`Font.underline_adjustment`). Text can be positioned by the upper +right corner of the text box or by the text baseline (see :attr:`Font.origin`). +Finally, a font's vertical and horizontal size can be adjusted separately +(see :attr:`Font.size`). +The :any:`pygame.examples.freetype_misc ` +example shows these features in use. + +The pygame package does not import ``freetype`` automatically when +loaded. This module must be imported explicitly to be used. :: + + import pygame + import pygame.freetype + +.. versionadded:: 1.9.2 :mod:`freetype` + + +.. function:: get_error + + | :sl:`Return the latest FreeType error` + | :sg:`get_error() -> str` + | :sg:`get_error() -> None` + + Return a description of the last error which occurred in the FreeType2 + library, or ``None`` if no errors have occurred. + +.. function:: get_version + + | :sl:`Return the FreeType version` + | :sg:`get_version(linked=True) -> (int, int, int)` + + Returns the version of the FreeType library in use by this module. ``linked=True`` + is the default behavior and returns the linked version of FreeType and ``linked=False`` + returns the compiled version of FreeType. + + Note that the ``freetype`` module depends on the FreeType 2 library. + It will not compile with the original FreeType 1.0. Hence, the first element + of the tuple will always be "2". + + .. versionchanged:: 2.2.0 ``linked`` keyword argument added and default behavior changed from returning compiled version to returning linked version + +.. function:: init + + | :sl:`Initialize the underlying FreeType library.` + | :sg:`init(cache_size=64, resolution=72) -> None` + + This function initializes the underlying FreeType library and must be + called before trying to use any of the functionality of the ``freetype`` + module. + + However, :func:`pygame.init()` will automatically call this function + if the ``freetype`` module is already imported. It is safe to call this + function more than once. + + Optionally, you may specify a default *cache_size* for the Glyph cache: the + maximum number of glyphs that will be cached at any given time by the + module. Exceedingly small values will be automatically tuned for + performance. Also a default pixel *resolution*, in dots per inch, can + be given to adjust font scaling. + +.. function:: quit + + | :sl:`Shut down the underlying FreeType library.` + | :sg:`quit() -> None` + + This function closes the ``freetype`` module. After calling this + function, you should not invoke any class, method or function related to the + ``freetype`` module as they are likely to fail or might give unpredictable + results. It is safe to call this function even if the module hasn't been + initialized yet. + +.. function:: get_init + + | :sl:`Returns True if the FreeType module is currently initialized.` + | :sg:`get_init() -> bool` + + Returns ``True`` if the ``pygame.freetype`` module is currently initialized. + + .. versionadded:: 1.9.5 + +.. function:: was_init + + | :sl:`DEPRECATED: Use get_init() instead.` + | :sg:`was_init() -> bool` + + DEPRECATED: Returns ``True`` if the ``pygame.freetype`` module is currently + initialized. Use ``get_init()`` instead. + +.. function:: get_cache_size + + | :sl:`Return the glyph case size` + | :sg:`get_cache_size() -> long` + + See :func:`pygame.freetype.init()`. + +.. function:: get_default_resolution + + | :sl:`Return the default pixel size in dots per inch` + | :sg:`get_default_resolution() -> long` + + Returns the default pixel size, in dots per inch, for the module. + The default is 72 DPI. + +.. function:: set_default_resolution + + | :sl:`Set the default pixel size in dots per inch for the module` + | :sg:`set_default_resolution([resolution])` + + Set the default pixel size, in dots per inch, for the module. If the + optional argument is omitted or zero the resolution is reset to 72 DPI. + +.. function:: SysFont + + | :sl:`create a Font object from the system fonts` + | :sg:`SysFont(name, size, bold=False, italic=False) -> Font` + + Return a new Font object that is loaded from the system fonts. The font will + match the requested *bold* and *italic* flags. Pygame uses a small set of + common font aliases. If the specific font you ask for is not available, a + reasonable alternative may be used. If a suitable system font is not found + this will fall back on loading the default pygame font. + + The font *name* can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + +.. function:: get_default_font + + | :sl:`Get the filename of the default font` + | :sg:`get_default_font() -> string` + + Return the filename of the default pygame font. This is not the full path + to the file. The file is usually in the same directory as the font module, + but can also be bundled in a separate archive. + +.. class:: Font + + | :sl:`Create a new Font instance from a supported font file.` + | :sg:`Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font` + | :sg:`Font(pathlib.Path) -> Font` + + Argument *file* can be either a string representing the font's filename, a + file-like object containing the font, or None; if None, a default, + Pygame, font is used. + + .. _freetype-font-size-argument: + + Optionally, a *size* argument may be specified to set the default size in + points, which determines the size of the rendered characters. + The size can also be passed explicitly to each method call. + Because of the way the caching system works, specifying a default size on + the constructor doesn't imply a performance gain over manually passing + the size on each function call. If the font is bitmap and no *size* + is given, the default size is set to the first available size for the font. + + If the font file has more than one font, the font to load can be chosen with + the *index* argument. An exception is raised for an out-of-range font index + value. + + The optional *resolution* argument sets the pixel size, in dots per inch, + for use in scaling glyphs for this Font instance. If 0 then the default + module value, set by :func:`init`, is used. The Font object's + resolution can only be changed by re-initializing the Font instance. + + The optional *ucs4* argument, an integer, sets the default text translation + mode: 0 (False) recognize UTF-16 surrogate pairs, any other value (True), + to treat Unicode text as UCS-4, with no surrogate pairs. See + :attr:`Font.ucs4`. + + .. attribute:: name + + | :sl:`Proper font name.` + | :sg:`name -> string` + + Read only. Returns the real (long) name of the font, as + recorded in the font file. + + .. attribute:: path + + | :sl:`Font file path` + | :sg:`path -> unicode` + + Read only. Returns the path of the loaded font file + + .. attribute:: size + + | :sl:`The default point size used in rendering` + | :sg:`size -> float` + | :sg:`size -> (float, float)` + + Get or set the default size for text metrics and rendering. It can be + a single point size, given as a Python ``int`` or ``float``, or a + font ppem (width, height) ``tuple``. Size values are non-negative. + A zero size or width represents an undefined size. In this case + the size must be given as a method argument, or an exception is + raised. A zero width but non-zero height is a ValueError. + + For a scalable font, a single number value is equivalent to a tuple + with width equal height. A font can be stretched vertically with + height set greater than width, or horizontally with width set + greater than height. For embedded bitmaps, as listed by :meth:`get_sizes`, + use the nominal width and height to select an available size. + + Font size differs for a non-scalable, bitmap, font. During a + method call it must match one of the available sizes returned by + method :meth:`get_sizes`. If not, an exception is raised. + If the size is a single number, the size is first matched against the + point size value. If no match, then the available size with the + same nominal width and height is chosen. + + .. method:: get_rect + + | :sl:`Return the size and offset of rendered text` + | :sg:`get_rect(text, style=STYLE_DEFAULT, rotation=0, size=0) -> rect` + + Gets the final dimensions and origin, in pixels, of *text* using the + optional *size* in points, *style*, and *rotation*. For other + relevant render properties, and for any optional argument not given, + the default values set for the :class:`Font` instance are used. + + Returns a :class:`Rect ` instance containing the + width and height of the text's bounding box and the position of the + text's origin. + The origin is useful in aligning separately rendered pieces of text. + It gives the baseline position and bearing at the start of the text. + See the :meth:`render_to` method for an example. + + If *text* is a char (byte) string, its encoding is assumed to be + ``LATIN1``. + + Optionally, *text* can be ``None``, which will return the bounding + rectangle for the text passed to a previous :meth:`get_rect`, + :meth:`render`, :meth:`render_to`, :meth:`render_raw`, or + :meth:`render_raw_to` call. See :meth:`render_to` for more + details. + + .. method:: get_metrics + + | :sl:`Return the glyph metrics for the given text` + | :sg:`get_metrics(text, size=0) -> [(...), ...]` + + Returns the glyph metrics for each character in *text*. + + The glyph metrics are returned as a list of tuples. Each tuple gives + metrics of a single character glyph. The glyph metrics are: + + :: + + (min_x, max_x, min_y, max_y, horizontal_advance_x, horizontal_advance_y) + + The bounding box min_x, max_x, min_y, and max_y values are returned as + grid-fitted pixel coordinates of type int. The advance values are + float values. + + The calculations are done using the font's default size in points. + Optionally you may specify another point size with the *size* argument. + + The metrics are adjusted for the current rotation, strong, and oblique + settings. + + If text is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + .. attribute:: height + + | :sl:`The unscaled height of the font in font units` + | :sg:`height -> int` + + Read only. Gets the height of the font. This is the average value of all + glyphs in the font. + + .. attribute:: ascender + + | :sl:`The unscaled ascent of the font in font units` + | :sg:`ascender -> int` + + Read only. Return the number of units from the font's baseline to + the top of the bounding box. + + .. attribute:: descender + + | :sl:`The unscaled descent of the font in font units` + | :sg:`descender -> int` + + Read only. Return the height in font units for the font descent. + The descent is the number of units from the font's baseline to the + bottom of the bounding box. + + .. method:: get_sized_ascender + + | :sl:`The scaled ascent of the font in pixels` + | :sg:`get_sized_ascender(=0) -> int` + + Return the number of units from the font's baseline to the top of the + bounding box. It is not adjusted for strong or rotation. + + .. method:: get_sized_descender + + | :sl:`The scaled descent of the font in pixels` + | :sg:`get_sized_descender(=0) -> int` + + Return the number of pixels from the font's baseline to the top of the + bounding box. It is not adjusted for strong or rotation. + + .. method:: get_sized_height + + | :sl:`The scaled height of the font in pixels` + | :sg:`get_sized_height(=0) -> int` + + Returns the height of the font. This is the average value of all + glyphs in the font. It is not adjusted for strong or rotation. + + .. method:: get_sized_glyph_height + + | :sl:`The scaled bounding box height of the font in pixels` + | :sg:`get_sized_glyph_height(=0) -> int` + + Return the glyph bounding box height of the font in pixels. + This is the average value of all glyphs in the font. + It is not adjusted for strong or rotation. + + .. method:: get_sizes + + | :sl:`return the available sizes of embedded bitmaps` + | :sg:`get_sizes() -> [(int, int, int, float, float), ...]` + | :sg:`get_sizes() -> []` + + Returns a list of tuple records, one for each point size + supported. Each tuple containing the point size, the height in pixels, + width in pixels, horizontal ppem (nominal width) in fractional pixels, + and vertical ppem (nominal height) in fractional pixels. + + .. method:: render + + | :sl:`Return rendered text as a surface` + | :sg:`render(text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> (Surface, Rect)` + + Returns a new :class:`Surface `, + with the text rendered to it + in the color given by 'fgcolor'. If no foreground color is given, + the default foreground color, :attr:`fgcolor ` is used. + If ``bgcolor`` is given, the surface + will be filled with this color. When no background color is given, + the surface background is transparent, zero alpha. Normally the returned + surface has a 32 bit pixel size. However, if ``bgcolor`` is ``None`` + and anti-aliasing is disabled a monochrome 8 bit colorkey surface, + with colorkey set for the background color, is returned. + + The return value is a tuple: the new surface and the bounding + rectangle giving the size and origin of the rendered text. + + If an empty string is passed for text then the returned Rect is zero + width and the height of the font. + + Optional *fgcolor*, *style*, *rotation*, and *size* arguments override + the default values set for the :class:`Font` instance. + + If *text* is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + Optionally, *text* can be ``None``, which will render the text + passed to a previous :meth:`get_rect`, :meth:`render`, :meth:`render_to`, + :meth:`render_raw`, or :meth:`render_raw_to` call. + See :meth:`render_to` for details. + + .. method:: render_to + + | :sl:`Render text onto an existing surface` + | :sg:`render_to(surf, dest, text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> Rect` + + Renders the string *text* to the :mod:`pygame.Surface` *surf*, + at position *dest*, a (x, y) surface coordinate pair. + If either x or y is not an integer it is converted to one if possible. + Any sequence where the first two items are x and y positional elements + is accepted, including a :class:`Rect ` instance. + As with :meth:`render`, + optional *fgcolor*, *style*, *rotation*, and *size* argument are + available. + + If a background color *bgcolor* is given, the text bounding box is + first filled with that color. The text is blitted next. + Both the background fill and text rendering involve full alpha blits. + That is, the alpha values of the foreground, background, and destination + target surface all affect the blit. + + The return value is a rectangle giving the size and position of the + rendered text within the surface. + + If an empty string is passed for text then the returned + :class:`Rect ` is zero width and the height of the font. + The rect will test False. + + Optionally, *text* can be set ``None``, which will re-render text + passed to a previous :meth:`render_to`, :meth:`get_rect`, :meth:`render`, + :meth:`render_raw`, or :meth:`render_raw_to` call. Primarily, this + feature is an aid to using :meth:`render_to` in combination with + :meth:`get_rect`. An example: :: + + def word_wrap(surf, text, font, color=(0, 0, 0)): + font.origin = True + words = text.split(' ') + width, height = surf.get_size() + line_spacing = font.get_sized_height() + 2 + x, y = 0, line_spacing + space = font.get_rect(' ') + for word in words: + bounds = font.get_rect(word) + if x + bounds.width + bounds.x >= width: + x, y = 0, y + line_spacing + if x + bounds.width + bounds.x >= width: + raise ValueError("word too wide for the surface") + if y + bounds.height - bounds.y >= height: + raise ValueError("text to long for the surface") + font.render_to(surf, (x, y), None, color) + x += bounds.width + space.width + return x, y + + When :meth:`render_to` is called with the same + font properties ― :attr:`size`, :attr:`style`, :attr:`strength`, + :attr:`wide`, :attr:`antialiased`, :attr:`vertical`, :attr:`rotation`, + :attr:`kerning`, and :attr:`use_bitmap_strikes` ― as :meth:`get_rect`, + :meth:`render_to` will use the layout calculated by :meth:`get_rect`. + Otherwise, :meth:`render_to` will recalculate the layout if called + with a text string or one of the above properties has changed + after the :meth:`get_rect` call. + + If *text* is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + .. method:: render_raw + + | :sl:`Return rendered text as a string of bytes` + | :sg:`render_raw(text, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> (bytes, (int, int))` + + Like :meth:`render` but with the pixels returned as a byte string + of 8-bit gray-scale values. The foreground color is 255, the + background 0, useful as an alpha mask for a foreground pattern. + + .. method:: render_raw_to + + | :sl:`Render text into an array of ints` + | :sg:`render_raw_to(array, text, dest=None, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> Rect` + + Render to an array object exposing an array struct interface. The array + must be two dimensional with integer items. The default *dest* value, + ``None``, is equivalent to position (0, 0). See :meth:`render_to`. + As with the other render methods, *text* can be ``None`` to + render a text string passed previously to another method. + + The return value is a :func:`pygame.Rect` giving the size and position of + the rendered text. + + .. attribute:: style + + | :sl:`The font's style flags` + | :sg:`style -> int` + + Gets or sets the default style of the Font. This default style will be + used for all text rendering and size calculations unless overridden + specifically a render or :meth:`get_rect` call. + The style value may be a bit-wise OR of one or more of the following + constants: + + :: + + STYLE_NORMAL + STYLE_UNDERLINE + STYLE_OBLIQUE + STYLE_STRONG + STYLE_WIDE + STYLE_DEFAULT + + These constants may be found on the FreeType constants module. + Optionally, the default style can be modified or obtained accessing the + individual style attributes (underline, oblique, strong). + + The ``STYLE_OBLIQUE`` and ``STYLE_STRONG`` styles are for + scalable fonts only. An attempt to set either for a bitmap font raises + an AttributeError. An attempt to set either for an inactive font, + as returned by ``Font.__new__()``, raises a RuntimeError. + + Assigning ``STYLE_DEFAULT`` to the :attr:`style` property leaves + the property unchanged, as this property defines the default. + The :attr:`style` property will never return ``STYLE_DEFAULT``. + + .. attribute:: underline + + | :sl:`The state of the font's underline style flag` + | :sg:`underline -> bool` + + Gets or sets whether the font will be underlined when drawing text. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the 'style' parameter. + + .. attribute:: strong + + | :sl:`The state of the font's strong style flag` + | :sg:`strong -> bool` + + Gets or sets whether the font will be bold when drawing text. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the 'style' parameter. + + .. attribute:: oblique + + | :sl:`The state of the font's oblique style flag` + | :sg:`oblique -> bool` + + Gets or sets whether the font will be rendered as oblique. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the *style* parameter. + + The oblique style is only supported for scalable (outline) fonts. + An attempt to set this style on a bitmap font will raise an + AttributeError. If the font object is inactive, as returned by + ``Font.__new__()``, setting this property raises a RuntimeError. + + .. attribute:: wide + + | :sl:`The state of the font's wide style flag` + | :sg:`wide -> bool` + + Gets or sets whether the font will be stretched horizontally + when drawing text. It produces a result similar to + :class:`pygame.font.Font`'s bold. This style not available for + rotated text. + + .. attribute:: strength + + | :sl:`The strength associated with the strong or wide font styles` + | :sg:`strength -> float` + + The amount by which a font glyph's size is enlarged for the + strong or wide transformations, as a fraction of the untransformed + size. For the wide style only the horizontal dimension is + increased. For strong text both the horizontal and vertical + dimensions are enlarged. A wide style of strength 0.08333 ( 1/12 ) is + equivalent to the :class:`pygame.font.Font` bold style. + The default is 0.02778 ( 1/36 ). + + The strength style is only supported for scalable (outline) fonts. + An attempt to set this property on a bitmap font will raise an + AttributeError. If the font object is inactive, as returned by + ``Font.__new__()``, assignment to this property raises a RuntimeError. + + .. attribute:: underline_adjustment + + | :sl:`Adjustment factor for the underline position` + | :sg:`underline_adjustment -> float` + + Gets or sets a factor which, when positive, is multiplied with the + font's underline offset to adjust the underline position. A negative + value turns an underline into a strike-through or overline. It is + multiplied with the ascender. Accepted values range between -2.0 and 2.0 + inclusive. A value of 0.5 closely matches Tango underlining. A value of + 1.0 mimics :class:`pygame.font.Font` underlining. + + .. attribute:: fixed_width + + | :sl:`Gets whether the font is fixed-width` + | :sg:`fixed_width -> bool` + + Read only. Returns ``True`` if the font contains fixed-width + characters (for example Courier, Bitstream Vera Sans Mono, Andale Mono). + + .. attribute:: fixed_sizes + + | :sl:`the number of available bitmap sizes for the font` + | :sg:`fixed_sizes -> int` + + Read only. Returns the number of point sizes for which the font contains + bitmap character images. If zero then the font is not a bitmap font. + A scalable font may contain pre-rendered point sizes as strikes. + + .. attribute:: scalable + + | :sl:`Gets whether the font is scalable` + | :sg:`scalable -> bool` + + Read only. Returns ``True`` if the font contains outline glyphs. + If so, the point size is not limited to available bitmap sizes. + + .. attribute:: use_bitmap_strikes + + | :sl:`allow the use of embedded bitmaps in an outline font file` + | :sg:`use_bitmap_strikes -> bool` + + Some scalable fonts include embedded bitmaps for particular point + sizes. This property controls whether or not those bitmap strikes + are used. Set it ``False`` to disable the loading of any bitmap + strike. Set it ``True``, the default, to permit bitmap strikes + for a non-rotated render with no style other than :attr:`wide` or + :attr:`underline`. This property is ignored for bitmap fonts. + + See also :attr:`fixed_sizes` and :meth:`get_sizes`. + + .. attribute:: antialiased + + | :sl:`Font anti-aliasing mode` + | :sg:`antialiased -> bool` + + Gets or sets the font's anti-aliasing mode. This defaults to + ``True`` on all fonts, which are rendered with full 8 bit blending. + + Set to ``False`` to do monochrome rendering. This should + provide a small speed gain and reduce cache memory size. + + .. attribute:: kerning + + | :sl:`Character kerning mode` + | :sg:`kerning -> bool` + + Gets or sets the font's kerning mode. This defaults to ``False`` + on all fonts, which will be rendered without kerning. + + Set to ``True`` to add kerning between character pairs, if supported + by the font, when positioning glyphs. + + .. attribute:: vertical + + | :sl:`Font vertical mode` + | :sg:`vertical -> bool` + + Gets or sets whether the characters are laid out vertically rather + than horizontally. May be useful when rendering Kanji or some other + vertical script. + + Set to ``True`` to switch to a vertical text layout. The default + is ``False``, place horizontally. + + Note that the :class:`Font` class does not automatically determine + script orientation. Vertical layout must be selected explicitly. + + Also note that several font formats (especially bitmap based ones) don't + contain the necessary metrics to draw glyphs vertically, so drawing in + those cases will give unspecified results. + + .. attribute:: rotation + + | :sl:`text rotation in degrees counterclockwise` + | :sg:`rotation -> int` + + Gets or sets the baseline angle of the rendered text. The angle is + represented as integer degrees. The default angle is 0, with horizontal + text rendered along the X-axis, and vertical text along the Y-axis. + A positive value rotates these axes counterclockwise that many degrees. + A negative angle corresponds to a clockwise rotation. The rotation + value is normalized to a value within the range 0 to 359 inclusive + (eg. 390 -> 390 - 360 -> 30, -45 -> 360 + -45 -> 315, + 720 -> 720 - (2 * 360) -> 0). + + Only scalable (outline) fonts can be rotated. An attempt to change + the rotation of a bitmap font raises an AttributeError. + An attempt to change the rotation of an inactive font instance, as + returned by ``Font.__new__()``, raises a RuntimeError. + + .. attribute:: fgcolor + + | :sl:`default foreground color` + | :sg:`fgcolor -> Color` + + Gets or sets the default glyph rendering color. It is initially opaque + black ― (0, 0, 0, 255). Applies to :meth:`render` and :meth:`render_to`. + + .. attribute:: bgcolor + + | :sl:`default background color` + | :sg:`bgcolor -> Color` + + Gets or sets the default background rendering color. Initially it is + unset and text will render with a transparent background by default. + Applies to :meth:`render` and :meth:`render_to`. + + .. versionadded:: 2.0.0 + + .. attribute:: origin + + | :sl:`Font render to text origin mode` + | :sg:`origin -> bool` + + If set ``True``, :meth:`render_to` and :meth:`render_raw_to` will + take the *dest* position to be that of the text origin, as opposed to + the top-left corner of the bounding box. See :meth:`get_rect` for + details. + + .. attribute:: pad + + | :sl:`padded boundary mode` + | :sg:`pad -> bool` + + If set ``True``, then the text boundary rectangle will be inflated + to match that of :class:`font.Font `. + Otherwise, the boundary rectangle is just large enough for the text. + + .. attribute:: ucs4 + + | :sl:`Enable UCS-4 mode` + | :sg:`ucs4 -> bool` + + Gets or sets the decoding of Unicode text. By default, the + freetype module performs UTF-16 surrogate pair decoding on Unicode text. + This allows 32-bit escape sequences ('\Uxxxxxxxx') between 0x10000 and + 0x10FFFF to represent their corresponding UTF-32 code points on Python + interpreters built with a UCS-2 Unicode type (on Windows, for instance). + It also means character values within the UTF-16 surrogate area (0xD800 + to 0xDFFF) are considered part of a surrogate pair. A malformed surrogate + pair will raise a UnicodeEncodeError. Setting ucs4 ``True`` turns + surrogate pair decoding off, allowing access the full UCS-4 character + range to a Python interpreter built with four-byte Unicode character + support. + + .. attribute:: resolution + + | :sl:`Pixel resolution in dots per inch` + | :sg:`resolution -> int` + + Read only. Gets pixel size used in scaling font glyphs for this + :class:`Font` instance. diff --git a/docs/ref/gfxdraw.rst b/docs/ref/gfxdraw.rst new file mode 100644 index 0000000..28153a3 --- /dev/null +++ b/docs/ref/gfxdraw.rst @@ -0,0 +1,628 @@ +.. include:: common.txt + +:mod:`pygame.gfxdraw` +===================== + +.. module:: pygame.gfxdraw + :synopsis: pygame module for drawing shapes + +| :sl:`pygame module for drawing shapes` + +**EXPERIMENTAL!**: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release. + +The pygame package does not import gfxdraw automatically when loaded, so it +must imported explicitly to be used. + +:: + + import pygame + import pygame.gfxdraw + +For all functions the arguments are strictly positional and integers are +accepted for coordinates and radii. The ``color`` argument can be one of the +following formats: + + - a :mod:`pygame.Color` object + - an ``(RGB)`` triplet (tuple/list) + - an ``(RGBA)`` quadruplet (tuple/list) + +The functions :meth:`rectangle` and :meth:`box` will accept any ``(x, y, w, h)`` +sequence for their ``rect`` argument, though :mod:`pygame.Rect` instances are +preferred. + +To draw a filled antialiased shape, first use the antialiased (aa*) version +of the function, and then use the filled (filled_*) version. +For example: + +:: + + col = (255, 0, 0) + surf.fill((255, 255, 255)) + pygame.gfxdraw.aacircle(surf, x, y, 30, col) + pygame.gfxdraw.filled_circle(surf, x, y, 30, col) + + +.. note:: + For threading, each of the functions releases the GIL during the C part of + the call. + +.. note:: + See the :mod:`pygame.draw` module for alternative draw methods. + The ``pygame.gfxdraw`` module differs from the :mod:`pygame.draw` module in + the API it uses and the different draw functions available. + ``pygame.gfxdraw`` wraps the primitives from the library called SDL_gfx, + rather than using modified versions. + +.. versionadded:: 1.9.0 + + +.. function:: pixel + + | :sl:`draw a pixel` + | :sg:`pixel(surface, x, y, color) -> None` + + Draws a single pixel, at position (x ,y), on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the pixel + :param int y: y coordinate of the pixel + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.pixel ## + +.. function:: hline + + | :sl:`draw a horizontal line` + | :sg:`hline(surface, x1, x2, y, color) -> None` + + Draws a straight horizontal line (``(x1, y)`` to ``(x2, y)``) on the given + surface. There are no endcaps. + + :param Surface surface: surface to draw on + :param int x1: x coordinate of one end of the line + :param int x2: x coordinate of the other end of the line + :param int y: y coordinate of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.hline ## + +.. function:: vline + + | :sl:`draw a vertical line` + | :sg:`vline(surface, x, y1, y2, color) -> None` + + Draws a straight vertical line (``(x, y1)`` to ``(x, y2)``) on the given + surface. There are no endcaps. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the line + :param int y1: y coordinate of one end of the line + :param int y2: y coordinate of the other end of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.vline ## + +.. function:: line + + | :sl:`draw a line` + | :sg:`line(surface, x1, y1, x2, y2, color) -> None` + + Draws a straight line (``(x1, y1)`` to ``(x2, y2)``) on the given surface. + There are no endcaps. + + :param Surface surface: surface to draw on + :param int x1: x coordinate of one end of the line + :param int y1: y coordinate of one end of the line + :param int x2: x coordinate of the other end of the line + :param int y2: y coordinate of the other end of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.line ## + +.. function:: rectangle + + | :sl:`draw a rectangle` + | :sg:`rectangle(surface, rect, color) -> None` + + Draws an unfilled rectangle on the given surface. For a filled rectangle use + :meth:`box`. + + :param Surface surface: surface to draw on + :param Rect rect: rectangle to draw, position and dimensions + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + The ``rect.bottom`` and ``rect.right`` attributes of a :mod:`pygame.Rect` + always lie one pixel outside of its actual border. Therefore, these + values will not be included as part of the drawing. + + .. ## pygame.gfxdraw.rectangle ## + +.. function:: box + + | :sl:`draw a filled rectangle` + | :sg:`box(surface, rect, color) -> None` + + Draws a filled rectangle on the given surface. For an unfilled rectangle use + :meth:`rectangle`. + + :param Surface surface: surface to draw on + :param Rect rect: rectangle to draw, position and dimensions + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + The ``rect.bottom`` and ``rect.right`` attributes of a :mod:`pygame.Rect` + always lie one pixel outside of its actual border. Therefore, these + values will not be included as part of the drawing. + + .. note:: + The :func:`pygame.Surface.fill` method works just as well for drawing + filled rectangles. In fact :func:`pygame.Surface.fill` can be hardware + accelerated on some platforms with both software and hardware display + modes. + + .. ## pygame.gfxdraw.box ## + +.. function:: circle + + | :sl:`draw a circle` + | :sg:`circle(surface, x, y, r, color) -> None` + + Draws an unfilled circle on the given surface. For a filled circle use + :meth:`filled_circle`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.circle ## + +.. function:: aacircle + + | :sl:`draw an antialiased circle` + | :sg:`aacircle(surface, x, y, r, color) -> None` + + Draws an unfilled antialiased circle on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aacircle ## + +.. function:: filled_circle + + | :sl:`draw a filled circle` + | :sg:`filled_circle(surface, x, y, r, color) -> None` + + Draws a filled circle on the given surface. For an unfilled circle use + :meth:`circle`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_circle ## + +.. function:: ellipse + + | :sl:`draw an ellipse` + | :sg:`ellipse(surface, x, y, rx, ry, color) -> None` + + Draws an unfilled ellipse on the given surface. For a filled ellipse use + :meth:`filled_ellipse`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.ellipse ## + +.. function:: aaellipse + + | :sl:`draw an antialiased ellipse` + | :sg:`aaellipse(surface, x, y, rx, ry, color) -> None` + + Draws an unfilled antialiased ellipse on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aaellipse ## + +.. function:: filled_ellipse + + | :sl:`draw a filled ellipse` + | :sg:`filled_ellipse(surface, x, y, rx, ry, color) -> None` + + Draws a filled ellipse on the given surface. For an unfilled ellipse use + :meth:`ellipse`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_ellipse ## + +.. function:: arc + + | :sl:`draw an arc` + | :sg:`arc(surface, x, y, r, start_angle, stop_angle, color) -> None` + + Draws an arc on the given surface. For an arc with its endpoints connected + to its center use :meth:`pie`. + + The two angle arguments are given in degrees and indicate the start and stop + positions of the arc. The arc is drawn in a clockwise direction from the + ``start_angle`` to the ``stop_angle``. If ``start_angle == stop_angle``, + nothing will be drawn + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the arc + :param int y: y coordinate of the center of the arc + :param int r: radius of the arc + :param int start_angle: start angle in degrees + :param int stop_angle: stop angle in degrees + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + This function uses *degrees* while the :func:`pygame.draw.arc` function + uses *radians*. + + .. ## pygame.gfxdraw.arc ## + +.. function:: pie + + | :sl:`draw a pie` + | :sg:`pie(surface, x, y, r, start_angle, stop_angle, color) -> None` + + Draws an unfilled pie on the given surface. A pie is an :meth:`arc` with its + endpoints connected to its center. + + The two angle arguments are given in degrees and indicate the start and stop + positions of the pie. The pie is drawn in a clockwise direction from the + ``start_angle`` to the ``stop_angle``. If ``start_angle == stop_angle``, + a straight line will be drawn from the center position at the given angle, + to a length of the radius. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the pie + :param int y: y coordinate of the center of the pie + :param int r: radius of the pie + :param int start_angle: start angle in degrees + :param int stop_angle: stop angle in degrees + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.pie ## + +.. function:: trigon + + | :sl:`draw a trigon/triangle` + | :sg:`trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws an unfilled trigon (triangle) on the given surface. For a filled + trigon use :meth:`filled_trigon`. + + A trigon can also be drawn using :meth:`polygon` e.g. + ``polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.trigon ## + +.. function:: aatrigon + + | :sl:`draw an antialiased trigon/triangle` + | :sg:`aatrigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws an unfilled antialiased trigon (triangle) on the given surface. + + An aatrigon can also be drawn using :meth:`aapolygon` e.g. + ``aapolygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aatrigon ## + +.. function:: filled_trigon + + | :sl:`draw a filled trigon/triangle` + | :sg:`filled_trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws a filled trigon (triangle) on the given surface. For an unfilled + trigon use :meth:`trigon`. + + A filled_trigon can also be drawn using :meth:`filled_polygon` e.g. + ``filled_polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_trigon ## + +.. function:: polygon + + | :sl:`draw a polygon` + | :sg:`polygon(surface, points, color) -> None` + + Draws an unfilled polygon on the given surface. For a filled polygon use + :meth:`filled_polygon`. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.polygon ## + +.. function:: aapolygon + + | :sl:`draw an antialiased polygon` + | :sg:`aapolygon(surface, points, color) -> None` + + Draws an unfilled antialiased polygon on the given surface. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.aapolygon ## + +.. function:: filled_polygon + + | :sl:`draw a filled polygon` + | :sg:`filled_polygon(surface, points, color) -> None` + + Draws a filled polygon on the given surface. For an unfilled polygon use + :meth:`polygon`. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated)` + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.filled_polygon ## + +.. function:: textured_polygon + + | :sl:`draw a textured polygon` + | :sg:`textured_polygon(surface, points, texture, tx, ty) -> None` + + Draws a textured polygon on the given surface. For better performance, the + surface and the texture should have the same format. + + A per-pixel alpha texture blit to a per-pixel alpha surface will differ from + a :func:`pygame.Surface.blit` blit. Also, a per-pixel alpha texture cannot be + used with an 8-bit per pixel destination. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param Surface texture: texture to draw on the polygon + :param int tx: x offset of the texture + :param int ty: y offset of the texture + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.textured_polygon ## + +.. function:: bezier + + | :sl:`draw a Bezier curve` + | :sg:`bezier(surface, points, steps, color) -> None` + + Draws a Bézier curve on the given surface. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates used to form a + curve, where each *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param int steps: number of steps for the interpolation, the minimum is 2 + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``steps < 2`` + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.bezier ## + +.. ## pygame.gfxdraw ## diff --git a/docs/ref/image.rst b/docs/ref/image.rst new file mode 100644 index 0000000..ec2e4fc --- /dev/null +++ b/docs/ref/image.rst @@ -0,0 +1,375 @@ +.. include:: common.txt + +:mod:`pygame.image` +=================== + +.. module:: pygame.image + :synopsis: pygame module for loading and saving images + +| :sl:`pygame module for image transfer` + +The image module contains functions for loading and saving pictures, as well as +transferring Surfaces to formats usable by other packages. + +Note that there is no Image class; an image is loaded as a Surface object. The +Surface class allows manipulation (drawing lines, setting pixels, capturing +regions, etc.). + +In the vast majority of installations, pygame is built to support extended +formats, using the SDL_Image library behind the scenes. However, some +installations may only support uncompressed ``BMP`` images. With full image +support, the :func:`pygame.image.load()` function can load the following +formats. + + * ``BMP`` + + * ``GIF`` (non-animated) + + * ``JPEG`` + + * ``LBM`` (and ``PBM``, ``PGM``, ``PPM``) + + * ``PCX`` + + * ``PNG`` + + * ``PNM`` + + * ``SVG`` (limited support, using Nano SVG) + + * ``TGA`` (uncompressed) + + * ``TIFF`` + + * ``WEBP`` + + * ``XPM`` + + +.. versionadded:: 2.0 Loading SVG, WebP, PNM + +Saving images only supports a limited set of formats. You can save to the +following formats. + + * ``BMP`` + + * ``JPEG`` + + * ``PNG`` + + * ``TGA`` + + +``JPEG`` and ``JPG``, as well as ``TIF`` and ``TIFF`` refer to the same file format + +.. versionadded:: 1.8 Saving PNG and JPEG files. + + +.. function:: load + + | :sl:`load new image from a file (or file-like object)` + | :sg:`load(filename) -> Surface` + | :sg:`load(fileobj, namehint="") -> Surface` + + Load an image from a file source. You can pass either a filename, a Python + file-like object, or a pathlib.Path. + + Pygame will automatically determine the image type (e.g., ``GIF`` or bitmap) + and create a new Surface object from the data. In some cases it will need to + know the file extension (e.g., ``GIF`` images should end in ".gif"). If you + pass a raw file-like object, you may also want to pass the original filename + as the namehint argument. + + The returned Surface will contain the same color format, colorkey and alpha + transparency as the file it came from. You will often want to call + :func:`pygame.Surface.convert()` with no arguments, to create a copy that + will draw more quickly on the screen. + + For alpha transparency, like in .png images, use the + :func:`pygame.Surface.convert_alpha()` method after loading so that the + image has per pixel transparency. + + Pygame may not always be built to support all image formats. At minimum it + will support uncompressed ``BMP``. If :func:`pygame.image.get_extended()` + returns ``True``, you should be able to load most images (including PNG, JPG + and GIF). + + You should use :func:`os.path.join()` for compatibility. + + :: + + eg. asurf = pygame.image.load(os.path.join('data', 'bla.png')) + + .. ## pygame.image.load ## + +.. function:: save + + | :sl:`save an image to file (or file-like object)` + | :sg:`save(Surface, filename) -> None` + | :sg:`save(Surface, fileobj, namehint="") -> None` + + This will save your Surface as either a ``BMP``, ``TGA``, ``PNG``, or + ``JPEG`` image. If the filename extension is unrecognized it will default to + ``TGA``. Both ``TGA``, and ``BMP`` file formats create uncompressed files. + You can pass a filename, a pathlib.Path or a Python file-like object. + For file-like object, the image is saved to ``TGA`` format unless + a namehint with a recognizable extension is passed in. + + .. note:: When saving to a file-like object, it seems that for most formats, + the object needs to be flushed after saving to it to make loading + from it possible. + + .. versionchanged:: 1.8 Saving PNG and JPEG files. + .. versionchanged:: 2.0.0 + The ``namehint`` parameter was added to make it possible + to save other formats than ``TGA`` to a file-like object. + Saving to a file-like object with JPEG is possible. + + .. ## pygame.image.save ## + +.. function:: get_sdl_image_version + + | :sl:`get version number of the SDL_Image library being used` + | :sg:`get_sdl_image_version(linked=True) -> None` + | :sg:`get_sdl_image_version(linked=True) -> (major, minor, patch)` + + If pygame is built with extended image formats, then this function will + return the SDL_Image library's version number as a tuple of 3 integers + ``(major, minor, patch)``. If not, then it will return ``None``. + + ``linked=True`` is the default behavior and the function will return the + version of the library that Pygame is linked against, while ``linked=False`` + will return the version of the library that Pygame is compiled against. + + .. versionadded:: 2.0.0 + + .. versionchanged:: 2.2.0 ``linked`` keyword argument added and default behavior changed from returning compiled version to returning linked version + + .. ## pygame.image.get_sdl_image_version ## + +.. function:: get_extended + + | :sl:`test if extended image formats can be loaded` + | :sg:`get_extended() -> bool` + + If pygame is built with extended image formats this function will return + True. It is still not possible to determine which formats will be available, + but generally you will be able to load them all. + + .. ## pygame.image.get_extended ## + +.. function:: tostring + + | :sl:`transfer image to byte buffer` + | :sg:`tostring(Surface, format, flipped=False) -> bytes` + + Creates a string of bytes that can be transferred with the ``fromstring`` + or ``frombytes`` methods in other Python imaging packages. Some Python + image packages prefer their images in bottom-to-top format (PyOpenGL for + example). If you pass ``True`` for the flipped argument, the byte buffer + will be vertically flipped. + + The format argument is a string of one of the following values. Note that + only 8-bit Surfaces can use the "P" format. The other formats will work for + any Surface. Also note that other Python image packages support more formats + than pygame. + + * ``P``, 8-bit palettized Surfaces + + * ``RGB``, 24-bit image + + * ``RGBX``, 32-bit image with unused space + + * ``RGBA``, 32-bit image with an alpha channel + + * ``ARGB``, 32-bit image with alpha channel first + + * ``BGRA``, 32-bit image with alpha channel, red and blue channels swapped + + * ``RGBA_PREMULT``, 32-bit image with colors scaled by alpha channel + + * ``ARGB_PREMULT``, 32-bit image with colors scaled by alpha channel, alpha channel first + + .. note:: it is preferred to use :func:`tobytes` as of pygame 2.1.3 + + .. versionadded:: 2.1.3 BGRA format + .. ## pygame.image.tostring ## + +.. function:: tobytes + + | :sl:`transfer image to byte buffer` + | :sg:`tobytes(Surface, format, flipped=False) -> bytes` + + Creates a string of bytes that can be transferred with the ``fromstring`` + or ``frombytes`` methods in other Python imaging packages. Some Python + image packages prefer their images in bottom-to-top format (PyOpenGL for + example). If you pass ``True`` for the flipped argument, the byte buffer + will be vertically flipped. + + The format argument is a string of one of the following values. Note that + only 8-bit Surfaces can use the "P" format. The other formats will work for + any Surface. Also note that other Python image packages support more formats + than pygame. + + * ``P``, 8-bit palettized Surfaces + + * ``RGB``, 24-bit image + + * ``RGBX``, 32-bit image with unused space + + * ``RGBA``, 32-bit image with an alpha channel + + * ``ARGB``, 32-bit image with alpha channel first + + * ``BGRA``, 32-bit image with alpha channel, red and blue channels swapped + + * ``RGBA_PREMULT``, 32-bit image with colors scaled by alpha channel + + * ``ARGB_PREMULT``, 32-bit image with colors scaled by alpha channel, alpha channel first + + .. note:: this function is an alias for :func:`tostring`. The use of this + function is recommended over :func:`tostring` as of pygame 2.1.3. + This function was introduced so it matches nicely with other + libraries (PIL, numpy, etc), and with people's expectations. + + .. versionadded:: 2.1.3 + + .. ## pygame.image.tobytes ## + + +.. function:: fromstring + + | :sl:`create new Surface from a byte buffer` + | :sg:`fromstring(bytes, size, format, flipped=False) -> Surface` + + This function takes arguments similar to :func:`pygame.image.tostring()`. + The size argument is a pair of numbers representing the width and height. + Once the new Surface is created it is independent from the memory of the + bytes passed in. + + The bytes and format passed must compute to the exact size of image + specified. Otherwise a ``ValueError`` will be raised. + + See the :func:`pygame.image.frombuffer()` method for a potentially faster + way to transfer images into pygame. + + .. note:: it is preferred to use :func:`frombytes` as of pygame 2.1.3 + + .. ## pygame.image.fromstring ## + +.. function:: frombytes + + | :sl:`create new Surface from a byte buffer` + | :sg:`frombytes(bytes, size, format, flipped=False) -> Surface` + + This function takes arguments similar to :func:`pygame.image.tobytes()`. + The size argument is a pair of numbers representing the width and height. + Once the new Surface is created it is independent from the memory of the + bytes passed in. + + The bytes and format passed must compute to the exact size of image + specified. Otherwise a ``ValueError`` will be raised. + + See the :func:`pygame.image.frombuffer()` method for a potentially faster + way to transfer images into pygame. + + .. note:: this function is an alias for :func:`fromstring`. The use of this + function is recommended over :func:`fromstring` as of pygame 2.1.3. + This function was introduced so it matches nicely with other + libraries (PIL, numpy, etc), and with people's expectations. + + .. versionadded:: 2.1.3 + + .. ## pygame.image.frombytes ## + +.. function:: frombuffer + + | :sl:`create a new Surface that shares data inside a bytes buffer` + | :sg:`frombuffer(buffer, size, format) -> Surface` + + Create a new Surface that shares pixel data directly from a buffer. This + buffer can be bytes, a bytearray, a memoryview, a + :class:`pygame.BufferProxy`, or any object that supports the buffer protocol. + This method takes similar arguments to :func:`pygame.image.fromstring()`, but + is unable to vertically flip the source data. + + This will run much faster than :func:`pygame.image.fromstring`, since no + pixel data must be allocated and copied. + + It accepts the following 'format' arguments: + + * ``P``, 8-bit palettized Surfaces + + * ``RGB``, 24-bit image + + * ``BGR``, 24-bit image, red and blue channels swapped. + + * ``RGBX``, 32-bit image with unused space + + * ``RGBA``, 32-bit image with an alpha channel + + * ``ARGB``, 32-bit image with alpha channel first + + * ``BGRA``, 32-bit image with alpha channel, red and blue channels swapped + + .. versionadded:: 2.1.3 BGRA format + .. ## pygame.image.frombuffer ## + +.. function:: load_basic + + | :sl:`load new BMP image from a file (or file-like object)` + | :sg:`load_basic(file) -> Surface` + + Load an image from a file source. You can pass either a filename or a Python + file-like object, or a pathlib.Path. + + This function only supports loading "basic" image format, ie ``BMP`` + format. + This function is always available, no matter how pygame was built. + + .. ## pygame.image.load_basic ## + +.. function:: load_extended + + | :sl:`load an image from a file (or file-like object)` + | :sg:`load_extended(filename) -> Surface` + | :sg:`load_extended(fileobj, namehint="") -> Surface` + + This function is similar to :func:`pygame.image.load()`, except that this + function can only be used if pygame was built with extended image format + support. + + .. versionchanged:: 2.0.1 + This function is always available, but raises an + ``NotImplementedError`` if extended image formats are + not supported. + Previously, this function may or may not be + available, depending on the state of extended image + format support. + + .. ## pygame.image.load_extended ## + +.. function:: save_extended + + | :sl:`save a png/jpg image to file (or file-like object)` + | :sg:`save_extended(Surface, filename) -> None` + | :sg:`save_extended(Surface, fileobj, namehint="") -> None` + + This will save your Surface as either a ``PNG`` or ``JPEG`` image. + + In case the image is being saved to a file-like object, this function + uses the namehint argument to determine the format of the file being + saved. Saves to ``JPEG`` in case the namehint was not specified while + saving to a file-like object. + + .. versionchanged:: 2.0.1 + This function is always available, but raises an + ``NotImplementedError`` if extended image formats are + not supported. + Previously, this function may or may not be + available, depending on the state of extended image + format support. + + .. ## pygame.image.save_extended ## + +.. ## pygame.image ## diff --git a/docs/ref/joystick.rst b/docs/ref/joystick.rst new file mode 100644 index 0000000..dba5b20 --- /dev/null +++ b/docs/ref/joystick.rst @@ -0,0 +1,697 @@ +.. include:: common.txt + +:mod:`pygame.joystick` +====================== + +.. module:: pygame.joystick + :synopsis: Pygame module for interacting with joysticks, gamepads, and trackballs. + +| :sl:`Pygame module for interacting with joysticks, gamepads, and trackballs.` + +The joystick module manages the joystick devices on a computer. +Joystick devices include trackballs and video-game-style +gamepads, and the module allows the use of multiple buttons and "hats". +Computers may manage multiple joysticks at a time. + +Each instance of the Joystick class represents one gaming device plugged +into the computer. If a gaming pad has multiple joysticks on it, then the +joystick object can actually represent multiple joysticks on that single +game device. + +For a quick way to initialise the joystick module and get a list of Joystick instances +use the following code:: + + pygame.joystick.init() + joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())] + +The following event types will be generated by the joysticks :: + + JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION + +And in pygame 2, which supports hotplugging:: + + JOYDEVICEADDED JOYDEVICEREMOVED + +Note that in pygame 2, joysticks events use a unique "instance ID". The device index +passed in the constructor to a Joystick object is not unique after devices have +been added and removed. You must call :meth:`Joystick.get_instance_id()` to find +the instance ID that was assigned to a Joystick on opening. + +The event queue needs to be pumped frequently for some of the methods to work. +So call one of pygame.event.get, pygame.event.wait, or pygame.event.pump regularly. + +To be able to get joystick events and update the joystick objects while the window +is not in focus, you may set the ``SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS`` environment +variable. See :ref:`environment variables ` for more details. + + +.. function:: init + + | :sl:`Initialize the joystick module.` + | :sg:`init() -> None` + + This function is called automatically by ``pygame.init()``. + + It initializes the joystick module. The module must be initialized before any + other functions will work. + + It is safe to call this function more than once. + + .. ## pygame.joystick.init ## + +.. function:: quit + + | :sl:`Uninitialize the joystick module.` + | :sg:`quit() -> None` + + Uninitialize the joystick module. After you call this any existing joystick + objects will no longer work. + + It is safe to call this function more than once. + + .. ## pygame.joystick.quit ## + +.. function:: get_init + + | :sl:`Returns True if the joystick module is initialized.` + | :sg:`get_init() -> bool` + + Test if the ``pygame.joystick.init()`` function has been called. + + .. ## pygame.joystick.get_init ## + +.. function:: get_count + + | :sl:`Returns the number of joysticks.` + | :sg:`get_count() -> count` + + Return the number of joystick devices on the system. The count will be ``0`` + if there are no joysticks on the system. + + When you create Joystick objects using ``Joystick(id)``, you pass an integer + that must be lower than this count. + + .. ## pygame.joystick.get_count ## + +.. class:: Joystick + + | :sl:`Create a new Joystick object.` + | :sg:`Joystick(id) -> Joystick` + + Create a new joystick to access a physical device. The id argument must be a + value from ``0`` to ``pygame.joystick.get_count() - 1``. + + Joysticks are initialised on creation and are shut down when deallocated. + Once the device is initialized the pygame event queue will start receiving + events about its input. + + .. versionchanged:: 2.0.0 Joystick objects are now opened immediately on creation. + + .. method:: init + + | :sl:`initialize the Joystick` + | :sg:`init() -> None` + + Initialize the joystick, if it has been closed. It is safe to call this + even if the joystick is already initialized. + + .. deprecated:: 2.0.0 + + In future it will not be possible to reinitialise a closed Joystick + object. Will be removed in Pygame 2.1. + + .. ## Joystick.init ## + + .. method:: quit + + | :sl:`uninitialize the Joystick` + | :sg:`quit() -> None` + + Close a Joystick object. After this the pygame event queue will no longer + receive events from the device. + + It is safe to call this more than once. + + .. ## Joystick.quit ## + + .. method:: get_init + + | :sl:`check if the Joystick is initialized` + | :sg:`get_init() -> bool` + + Return True if the Joystick object is currently initialised. + + .. ## Joystick.get_init ## + + .. method:: get_id + + | :sl:`get the device index (deprecated)` + | :sg:`get_id() -> int` + + Returns the original device index for this device. This is the same + value that was passed to the ``Joystick()`` constructor. This method can + safely be called while the Joystick is not initialized. + + .. deprecated:: 2.0.0 + + The original device index is not useful in pygame 2. Use + :meth:`.get_instance_id` instead. Will be removed in Pygame 2.1. + + .. method:: get_instance_id() -> int + + | :sl:`get the joystick instance id` + | :sg:`get_instance_id() -> int` + + Get the joystick instance ID. This matches the ``instance_id`` field + that is given in joystick events. + + .. versionadded:: 2.0.0dev11 + + .. method:: get_guid() -> str + + | :sl:`get the joystick GUID` + | :sg:`get_guid() -> str` + + Get the GUID string. This identifies the exact hardware of the joystick + device. + + .. versionadded:: 2.0.0dev11 + + .. method:: get_power_level() -> str + + | :sl:`get the approximate power status of the device` + | :sg:`get_power_level() -> str` + + Get a string giving the power status of the device. + + One of: ``empty``, ``low``, ``medium``, ``full``, ``wired``, ``max``, or + ``unknown``. + + .. versionadded:: 2.0.0dev11 + + .. ## Joystick.get_id ## + + .. method:: get_name + + | :sl:`get the Joystick system name` + | :sg:`get_name() -> string` + + Returns the system name for this joystick device. It is unknown what name + the system will give to the Joystick, but it should be a unique name that + identifies the device. This method can safely be called while the + Joystick is not initialized. + + .. ## Joystick.get_name ## + + .. method:: get_numaxes + + | :sl:`get the number of axes on a Joystick` + | :sg:`get_numaxes() -> int` + + Returns the number of input axes are on a Joystick. There will usually be + two for the position. Controls like rudders and throttles are treated as + additional axes. + + The ``pygame.JOYAXISMOTION`` events will be in the range from ``-1.0`` + to ``1.0``. A value of ``0.0`` means the axis is centered. Gamepad devices + will usually be ``-1``, ``0``, or ``1`` with no values in between. Older + analog joystick axes will not always use the full ``-1`` to ``1`` range, + and the centered value will be some area around ``0``. + + Analog joysticks usually have a bit of noise in their axis, which will + generate a lot of rapid small motion events. + + .. ## Joystick.get_numaxes ## + + .. method:: get_axis + + | :sl:`get the current position of an axis` + | :sg:`get_axis(axis_number) -> float` + + Returns the current position of a joystick axis. The value will range + from ``-1`` to ``1`` with a value of ``0`` being centered. You may want + to take into account some tolerance to handle jitter, and joystick drift + may keep the joystick from centering at ``0`` or using the full range of + position values. + + The axis number must be an integer from ``0`` to ``get_numaxes() - 1``. + + When using gamepads both the control sticks and the analog triggers are + usually reported as axes. + + .. ## Joystick.get_axis ## + + .. method:: get_numballs + + | :sl:`get the number of trackballs on a Joystick` + | :sg:`get_numballs() -> int` + + Returns the number of trackball devices on a Joystick. These devices work + similar to a mouse but they have no absolute position; they only have + relative amounts of movement. + + The ``pygame.JOYBALLMOTION`` event will be sent when the trackball is + rolled. It will report the amount of movement on the trackball. + + .. ## Joystick.get_numballs ## + + .. method:: get_ball + + | :sl:`get the relative position of a trackball` + | :sg:`get_ball(ball_number) -> x, y` + + Returns the relative movement of a joystick button. The value is a ``x, y`` + pair holding the relative movement since the last call to get_ball. + + The ball number must be an integer from ``0`` to ``get_numballs() - 1``. + + .. ## Joystick.get_ball ## + + .. method:: get_numbuttons + + | :sl:`get the number of buttons on a Joystick` + | :sg:`get_numbuttons() -> int` + + Returns the number of pushable buttons on the joystick. These buttons + have a boolean (on or off) state. + + Buttons generate a ``pygame.JOYBUTTONDOWN`` and ``pygame.JOYBUTTONUP`` + event when they are pressed and released. + + .. ## Joystick.get_numbuttons ## + + .. method:: get_button + + | :sl:`get the current button state` + | :sg:`get_button(button) -> bool` + + Returns the current state of a joystick button. + + .. ## Joystick.get_button ## + + .. method:: get_numhats + + | :sl:`get the number of hat controls on a Joystick` + | :sg:`get_numhats() -> int` + + Returns the number of joystick hats on a Joystick. Hat devices are like + miniature digital joysticks on a joystick. Each hat has two axes of + input. + + The ``pygame.JOYHATMOTION`` event is generated when the hat changes + position. The ``position`` attribute for the event contains a pair of + values that are either ``-1``, ``0``, or ``1``. A position of ``(0, 0)`` + means the hat is centered. + + .. ## Joystick.get_numhats ## + + .. method:: get_hat + + | :sl:`get the position of a joystick hat` + | :sg:`get_hat(hat_number) -> x, y` + + Returns the current position of a position hat. The position is given as + two values representing the ``x`` and ``y`` position for the hat. ``(0, 0)`` + means centered. A value of ``-1`` means left/down and a value of ``1`` means + right/up: so ``(-1, 0)`` means left; ``(1, 0)`` means right; ``(0, 1)`` means + up; ``(1, 1)`` means upper-right; etc. + + This value is digital, ``i.e.``, each coordinate can be ``-1``, ``0`` or ``1`` + but never in-between. + + The hat number must be between ``0`` and ``get_numhats() - 1``. + + .. ## Joystick.get_hat ## + + .. method:: rumble + + | :sl:`Start a rumbling effect` + | :sg:`rumble(low_frequency, high_frequency, duration) -> bool` + + Start a rumble effect on the joystick, with the specified strength ranging + from 0 to 1. Duration is length of the effect, in ms. Setting the duration + to 0 will play the effect until another one overwrites it or + :meth:`Joystick.stop_rumble` is called. If an effect is already + playing, then it will be overwritten. + + Returns True if the rumble was played successfully or False if the + joystick does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + + .. versionadded:: 2.0.2 + + .. ## Joystick.rumble ## + + .. method:: stop_rumble + + | :sl:`Stop any rumble effect playing` + | :sg:`stop_rumble() -> None` + + Stops any rumble effect playing on the joystick. See + :meth:`Joystick.rumble` for more information. + + .. versionadded:: 2.0.2 + + .. ## Joystick.stop_rumble ## + + .. ## pygame.joystick.Joystick ## + +.. ## pygame.joystick ## + +.. figure:: code_examples/joystick_calls.png + :scale: 100 % + :alt: joystick module example + + Example code for joystick module. + +.. literalinclude:: ../../../examples/joystick.py + +.. _controller-mappings: + + +Common Controller Axis Mappings +=============================== + +Controller mappings are drawn from the underlying SDL library which pygame uses and they differ +between pygame 1 and pygame 2. Below are a couple of mappings for three popular controllers. + +Axis and hat mappings are listed from -1 to +1. + + +Nintendo Switch Left Joy-Con (pygame 2.x) +***************************************** + +The Nintendo Switch Left Joy-Con has 4 axes, 11 buttons, and 0 hats. The values for the 4 axes never change. +The controller is recognized as "Wireless Gamepad" + + +* **Buttons**:: + + D-pad Up - Button 0 + D-pad Down - Button 1 + D-pad Left - Button 2 + D-pad Right - Button 3 + SL - Button 4 + SR - Button 5 + - - Button 8 + Stick In - Button 10 + Capture - Button 13 + L - Button 14 + ZL - Button 15 + +* **Hat/JoyStick**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +Nintendo Switch Right Joy-Con (pygame 2.x) +****************************************** + +The Nintendo Switch Right Joy-Con has 4 axes, 11 buttons, and 0 hats. The values for the 4 axes never change. +The controller is recognized as "Wireless Gamepad" + + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + SL - Button 4 + SR - Button 5 + + - Button 9 + Stick In - Button 11 + Home - Button 12 + R - Button 14 + ZR - Button 15 + +* **Hat/JoyStick**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +Nintendo Switch Pro Controller (pygame 2.x) +******************************************* + +The Nintendo Switch Pro Controller has 6 axes, 16 buttons, and 0 hats. +The controller is recognized as "Nintendo Switch Pro Controller". + + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 2 + Up -> Down - Axis 3 + +* **Left Trigger**:: + + Out -> In - Axis 4 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + - Button - Button 4 + Home Button - Button 5 + + Button - Button 6 + L. Stick In - Button 7 + R. Stick In - Button 8 + Left Bumper - Button 9 + Right Bumper - Button 10 + D-pad Up - Button 11 + D-pad Down - Button 12 + D-pad Left - Button 13 + D-pad Right - Button 14 + Capture Button - Button 15 + + +XBox 360 Controller (pygame 2.x) +******************************** + +The Xbox 360 controller mapping has 6 axes, 11 buttons and 1 hat. +The controller is recognized as "Xbox 360 Controller". + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 3 + Up -> Down - Axis 4 + +* **Left Trigger**:: + + Out -> In - Axis 2 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + Back Button - Button 6 + Start Button - Button 7 + L. Stick In - Button 8 + R. Stick In - Button 9 + Guide Button - Button 10 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +Playstation 4 Controller (pygame 2.x) +************************************* + +The PlayStation 4 controller mapping has 6 axes and 16 buttons. +The controller is recognized as "PS4 Controller". + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 2 + Up -> Down - Axis 3 + +* **Left Trigger**:: + + Out -> In - Axis 4 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + Cross Button - Button 0 + Circle Button - Button 1 + Square Button - Button 2 + Triangle Button - Button 3 + Share Button - Button 4 + PS Button - Button 5 + Options Button - Button 6 + L. Stick In - Button 7 + R. Stick In - Button 8 + Left Bumper - Button 9 + Right Bumper - Button 10 + D-pad Up - Button 11 + D-pad Down - Button 12 + D-pad Left - Button 13 + D-pad Right - Button 14 + Touch Pad Click - Button 15 + +Playstation 5 Controller (pygame 2.x) +************************************* + +The PlayStation 5 controller mapping has 6 axes, 13 buttons, and 1 hat. +The controller is recognized as "Sony Interactive Entertainment Wireless Controller". + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 3 + Up -> Down - Axis 4 + +* **Left Trigger**:: + + Out -> In - Axis 2 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + Cross Button - Button 0 + Circle Button - Button 1 + Square Button - Button 2 + Triangle Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + Left Trigger - Button 6 + Right Trigger - Button 7 + Share Button - Button 8 + Options Button - Button 9 + PS Button - Button 10 + Left Stick in - Button 11 + Right Stick in - Button 12 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + + +XBox 360 Controller (pygame 1.x) +******************************** + +The Xbox 360 controller mapping has 5 axes, 10 buttons, and 1 hat. +The controller is recognized as "Controller (XBOX 360 For Windows)". + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 4 + Up -> Down - Axis 3 + +* **Left Trigger & Right Trigger**:: + + RT -> LT - Axis 2 + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + Back Button - Button 6 + Start Button - Button 7 + L. Stick In - Button 8 + R. Stick In - Button 9 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +Playstation 4 Controller (pygame 1.x) +************************************* + +The PlayStation 4 controller mapping has 6 axes, 14 buttons, and 1 hat. +The controller is recognized as "Wireless Controller". + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 2 + Up -> Down - Axis 3 + +* **Left Trigger**:: + + Out -> In - Axis 5 + +* **Right Trigger**:: + + Out -> In - Axis 4 + +* **Buttons**:: + + Cross Button - Button 0 + Circle Button - Button 1 + Square Button - Button 2 + Triangle Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + L. Trigger(Full)- Button 6 + R. Trigger(Full)- Button 7 + Share Button - Button 8 + Options Button - Button 9 + L. Stick In - Button 10 + R. Stick In - Button 11 + PS Button - Button 12 + Touch Pad Click - Button 13 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + diff --git a/docs/ref/key.rst b/docs/ref/key.rst new file mode 100644 index 0000000..134f254 --- /dev/null +++ b/docs/ref/key.rst @@ -0,0 +1,455 @@ +.. include:: common.txt + +:mod:`pygame.key` +================= + +.. module:: pygame.key + :synopsis: pygame module to work with the keyboard + +| :sl:`pygame module to work with the keyboard` + +This module contains functions for dealing with the keyboard. + +The :mod:`pygame.event` queue gets ``pygame.KEYDOWN`` and ``pygame.KEYUP`` +events when the keyboard buttons are pressed and released. Both events have +``key`` and ``mod`` attributes. + + * ``key``: an :ref:`integer ID ` representing every key + on the keyboard + * ``mod``: a bitmask of all the :ref:`modifier keys ` + that were in a pressed state when the event occurred + +The ``pygame.KEYDOWN`` event has the additional attributes ``unicode`` and +``scancode``. + + * ``unicode``: a single character string that is the fully translated + character entered, this takes into account the shift and composition keys + * ``scancode``: the platform-specific key code, which could be different from + keyboard to keyboard, but is useful for key selection of weird keys like + the multimedia keys + +.. versionadded:: 2.0.0 + The ``pygame.TEXTINPUT`` event is preferred to the ``unicode`` attribute + of ``pygame.KEYDOWN``. The attribute ``text`` contains the input. + + +.. _key-constants-label: + +The following is a list of all the constants (from :mod:`pygame.locals`) used to +represent keyboard keys. + +Portability note: The integers for key constants differ between pygame 1 and 2. +Always use key constants (``K_a``) rather than integers directly (``97``) so +that your key handling code works well on both pygame 1 and pygame 2. + + +:: + + pygame + Constant ASCII Description + --------------------------------- + K_BACKSPACE \b backspace + K_TAB \t tab + K_CLEAR clear + K_RETURN \r return + K_PAUSE pause + K_ESCAPE ^[ escape + K_SPACE space + K_EXCLAIM ! exclaim + K_QUOTEDBL " quotedbl + K_HASH # hash + K_DOLLAR $ dollar + K_AMPERSAND & ampersand + K_QUOTE quote + K_LEFTPAREN ( left parenthesis + K_RIGHTPAREN ) right parenthesis + K_ASTERISK * asterisk + K_PLUS + plus sign + K_COMMA , comma + K_MINUS - minus sign + K_PERIOD . period + K_SLASH / forward slash + K_0 0 0 + K_1 1 1 + K_2 2 2 + K_3 3 3 + K_4 4 4 + K_5 5 5 + K_6 6 6 + K_7 7 7 + K_8 8 8 + K_9 9 9 + K_COLON : colon + K_SEMICOLON ; semicolon + K_LESS < less-than sign + K_EQUALS = equals sign + K_GREATER > greater-than sign + K_QUESTION ? question mark + K_AT @ at + K_LEFTBRACKET [ left bracket + K_BACKSLASH \ backslash + K_RIGHTBRACKET ] right bracket + K_CARET ^ caret + K_UNDERSCORE _ underscore + K_BACKQUOTE ` grave + K_a a a + K_b b b + K_c c c + K_d d d + K_e e e + K_f f f + K_g g g + K_h h h + K_i i i + K_j j j + K_k k k + K_l l l + K_m m m + K_n n n + K_o o o + K_p p p + K_q q q + K_r r r + K_s s s + K_t t t + K_u u u + K_v v v + K_w w w + K_x x x + K_y y y + K_z z z + K_DELETE delete + K_KP0 keypad 0 + K_KP1 keypad 1 + K_KP2 keypad 2 + K_KP3 keypad 3 + K_KP4 keypad 4 + K_KP5 keypad 5 + K_KP6 keypad 6 + K_KP7 keypad 7 + K_KP8 keypad 8 + K_KP9 keypad 9 + K_KP_PERIOD . keypad period + K_KP_DIVIDE / keypad divide + K_KP_MULTIPLY * keypad multiply + K_KP_MINUS - keypad minus + K_KP_PLUS + keypad plus + K_KP_ENTER \r keypad enter + K_KP_EQUALS = keypad equals + K_UP up arrow + K_DOWN down arrow + K_RIGHT right arrow + K_LEFT left arrow + K_INSERT insert + K_HOME home + K_END end + K_PAGEUP page up + K_PAGEDOWN page down + K_F1 F1 + K_F2 F2 + K_F3 F3 + K_F4 F4 + K_F5 F5 + K_F6 F6 + K_F7 F7 + K_F8 F8 + K_F9 F9 + K_F10 F10 + K_F11 F11 + K_F12 F12 + K_F13 F13 + K_F14 F14 + K_F15 F15 + K_NUMLOCK numlock + K_CAPSLOCK capslock + K_SCROLLOCK scrollock + K_RSHIFT right shift + K_LSHIFT left shift + K_RCTRL right control + K_LCTRL left control + K_RALT right alt + K_LALT left alt + K_RMETA right meta + K_LMETA left meta + K_LSUPER left Windows key + K_RSUPER right Windows key + K_MODE mode shift + K_HELP help + K_PRINT print screen + K_SYSREQ sysrq + K_BREAK break + K_MENU menu + K_POWER power + K_EURO Euro + K_AC_BACK Android back button + + +.. _key-modifiers-label: + +The keyboard also has a list of modifier states (from :mod:`pygame.locals`) that +can be assembled by bitwise-ORing them together. + +:: + + pygame + Constant Description + ------------------------- + KMOD_NONE no modifier keys pressed + KMOD_LSHIFT left shift + KMOD_RSHIFT right shift + KMOD_SHIFT left shift or right shift or both + KMOD_LCTRL left control + KMOD_RCTRL right control + KMOD_CTRL left control or right control or both + KMOD_LALT left alt + KMOD_RALT right alt + KMOD_ALT left alt or right alt or both + KMOD_LMETA left meta + KMOD_RMETA right meta + KMOD_META left meta or right meta or both + KMOD_CAPS caps lock + KMOD_NUM num lock + KMOD_MODE AltGr + + +The modifier information is contained in the ``mod`` attribute of the +``pygame.KEYDOWN`` and ``pygame.KEYUP`` events. The ``mod`` attribute is a +bitmask of all the modifier keys that were in a pressed state when the event +occurred. The modifier information can be decoded using a bitwise AND (except +for ``KMOD_NONE``, which should be compared using equals ``==``). For example: + +:: + + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP: + if event.mod == pygame.KMOD_NONE: + print('No modifier keys were in a pressed state when this ' + 'event occurred.') + else: + if event.mod & pygame.KMOD_LSHIFT: + print('Left shift was in a pressed state when this event ' + 'occurred.') + if event.mod & pygame.KMOD_RSHIFT: + print('Right shift was in a pressed state when this event ' + 'occurred.') + if event.mod & pygame.KMOD_SHIFT: + print('Left shift or right shift or both were in a ' + 'pressed state when this event occurred.') + + + +.. function:: get_focused + + | :sl:`true if the display is receiving keyboard input from the system` + | :sg:`get_focused() -> bool` + + Returns ``True`` when the display window has keyboard focus from the + system. If the display needs to ensure it does not lose keyboard focus, it + can use :func:`pygame.event.set_grab()` to grab all input. + + .. ## pygame.key.get_focused ## + +.. function:: get_pressed + + | :sl:`get the state of all keyboard buttons` + | :sg:`get_pressed() -> bools` + + Returns a sequence of boolean values representing the state of every key on + the keyboard. Use the key constant values to index the array. A ``True`` + value means that the button is pressed. + + .. note:: + Getting the list of pushed buttons with this function is not the proper + way to handle text entry from the user. There is no way to know the order + of keys pressed, and rapidly pushed keys can be completely unnoticed + between two calls to ``pygame.key.get_pressed()``. There is also no way to + translate these pushed keys into a fully translated character value. See + the ``pygame.KEYDOWN`` events on the :mod:`pygame.event` queue for this + functionality. + + .. versionadded:: 2.2.0 + The collection of bools returned by ``get_pressed`` can not be iterated + over because the indexes of the internal tuple does not correpsond to the + keycodes. + + .. versionadded:: 2.5.0 + Iteration over the collection of bools returned by ``get_pressed`` is now + restored. However it still does not make sense to iterate over it. Currently. + + .. ## pygame.key.get_pressed ## + +.. function:: get_mods + + | :sl:`determine which modifier keys are being held` + | :sg:`get_mods() -> int` + + Returns a single integer representing a bitmask of all the modifier keys + being held. Using bitwise operators you can test if specific + :ref:`modifier keys ` are pressed. + + .. ## pygame.key.get_mods ## + +.. function:: set_mods + + | :sl:`temporarily set which modifier keys are pressed` + | :sg:`set_mods(int) -> None` + + Create a bitmask of the :ref:`modifier key constants ` + you want to impose on your program. + + .. ## pygame.key.set_mods ## + +.. function:: set_repeat + + | :sl:`control how held keys are repeated` + | :sg:`set_repeat() -> None` + | :sg:`set_repeat(delay) -> None` + | :sg:`set_repeat(delay, interval) -> None` + + When the keyboard repeat is enabled, keys that are held down will generate + multiple ``pygame.KEYDOWN`` events. The ``delay`` parameter is the number of + milliseconds before the first repeated ``pygame.KEYDOWN`` event will be sent. + After that, another ``pygame.KEYDOWN`` event will be sent every ``interval`` + milliseconds. If a ``delay`` value is provided and an ``interval`` value is + not provided or is 0, then the ``interval`` will be set to the same value as + ``delay``. + + To disable key repeat call this function with no arguments or with ``delay`` + set to 0. + + When pygame is initialized the key repeat is disabled. + + :raises ValueError: if ``delay`` or ``interval`` is < 0 + + .. versionchanged:: 2.0.0 A ``ValueError`` is now raised (instead of a + ``pygame.error``) if ``delay`` or ``interval`` is < 0. + + .. ## pygame.key.set_repeat ## + +.. function:: get_repeat + + | :sl:`see how held keys are repeated` + | :sg:`get_repeat() -> (delay, interval)` + + Get the ``delay`` and ``interval`` keyboard repeat values. Refer to + :func:`pygame.key.set_repeat()` for a description of these values. + + .. versionadded:: 1.8 + + .. ## pygame.key.get_repeat ## + +.. function:: name + + | :sl:`get the name of a key identifier` + | :sg:`name(key, use_compat=True) -> str` + + Get the descriptive name of the button from a keyboard button id constant. + Returns an empty string (``""``) if the key is not found. + + If ``use_compat`` argument is ``True`` (which is the default), this function + returns the legacy name of a key where applicable. The return value is + expected to be the same across different pygame versions (provided the + corresponding key constant exists and is unique). If the return value is + passed to the ``key_code`` function, the original constant will be returned. + + **Experimental:** ``use_compat`` paramater still in development for testing and feedback. It may change. + `Please leave use_compat feedback with authors `_ + + If this argument is ``False``, the returned name may be prettier to display + and may cover a wider range of keys than with ``use_compat``, but there are + no guarantees that this name will be the same across different pygame + versions. If the name returned is passed to the ``key_code`` function, the + original constant is returned back (this is an implementation detail which + may change later, do not rely on this) + + .. versionchanged:: 2.1.3 Added ``use_compat`` argument and guaranteed API stability for it + + .. ## pygame.key.name ## + +.. function:: key_code + + | :sl:`get the key identifier from a key name` + | :sg:`key_code(name=string) -> int` + + Get the key identifier code from the descriptive name of the key. This + returns an integer matching one of the K_* keycodes. For example: + + :: + + >>> pygame.key.key_code("return") == pygame.K_RETURN + True + >>> pygame.key.key_code("0") == pygame.K_0 + True + >>> pygame.key.key_code("space") == pygame.K_SPACE + True + + :raises ValueError: if the key name is not known. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.key_code ## + +.. function:: start_text_input + + | :sl:`start handling Unicode text input events` + | :sg:`start_text_input() -> None` + + Start receiving ``pygame.TEXTEDITING`` and ``pygame.TEXTINPUT`` + events. If applicable, show the on-screen keyboard or IME editor. + + For many languages, key presses will automatically generate a + corresponding ``pygame.TEXTINPUT`` event. Special keys like + escape or function keys, and certain key combinations will not + generate ``pygame.TEXTINPUT`` events. + + In other languages, entering a single symbol may require multiple + key presses, or a language-specific user interface. In this case, + ``pygame.TEXTINPUT`` events are preferable to ``pygame.KEYDOWN`` + events for text input. + + A ``pygame.TEXTEDITING`` event is received when an IME composition + is started or changed. It contains the composition ``text``, ``length``, + and editing ``start`` position within the composition (attributes + ``text``, ``length``, and ``start``, respectively). + When the composition is committed (or non-IME input is received), + a ``pygame.TEXTINPUT`` event is generated. + + Text input events handling is on by default. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.start_text_input ## + +.. function:: stop_text_input + + | :sl:`stop handling Unicode text input events` + | :sg:`stop_text_input() -> None` + + Stop receiving ``pygame.TEXTEDITING`` and ``pygame.TEXTINPUT`` + events. If an on-screen keyboard or IME editor was shown with + ``pygame.key.start_text_input()``, hide it again. + + Text input events handling is on by default. + + To avoid triggering the IME editor or the on-screen keyboard + when the user is holding down a key during gameplay, text input + should be disabled once text entry is finished, or when the user + clicks outside of a text box. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.stop_text_input ## + +.. function:: set_text_input_rect + + | :sl:`controls the position of the candidate list` + | :sg:`set_text_input_rect(Rect) -> None` + + This sets the rectangle used for typing with an IME. + It controls where the candidate list will open, if supported. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.set_text_input_rect ## + +.. ## pygame.key ## diff --git a/docs/ref/locals.rst b/docs/ref/locals.rst new file mode 100644 index 0000000..091dbaa --- /dev/null +++ b/docs/ref/locals.rst @@ -0,0 +1,27 @@ +.. include:: common.txt + +:mod:`pygame.locals` +==================== + +.. module:: pygame.locals + :synopsis: pygame constants + +| :sl:`pygame constants` + +This module contains various constants used by pygame. Its contents are +automatically placed in the pygame module namespace. However, an application +can use ``pygame.locals`` to include only the pygame constants with a ``from +pygame.locals import *``. + +Detailed descriptions of the various constants can be found throughout the +pygame documentation. Here are the locations of some of them. + + - The :mod:`pygame.display` module contains flags like ``FULLSCREEN`` used + by :func:`pygame.display.set_mode`. + - The :mod:`pygame.event` module contains the various event types. + - The :mod:`pygame.key` module lists the keyboard constants and modifiers + (``K_``\* and ``MOD_``\*) relating to the ``key`` and ``mod`` attributes of + the ``KEYDOWN`` and ``KEYUP`` events. + - The :mod:`pygame.time` module defines ``TIMER_RESOLUTION``. + +.. ## pygame.locals ## diff --git a/docs/ref/mask.rst b/docs/ref/mask.rst new file mode 100644 index 0000000..f4365cf --- /dev/null +++ b/docs/ref/mask.rst @@ -0,0 +1,642 @@ +.. include:: common.txt + +:mod:`pygame.mask` +================== + +.. module:: pygame.mask + :synopsis: pygame module for image masks. + +| :sl:`pygame module for image masks.` + +Useful for fast pixel perfect collision detection. A mask uses 1 bit per-pixel +to store which parts collide. + +.. versionadded:: 1.8 + +.. versionchanged:: 2.0.2 Mask functions now support keyword arguments. + +.. versionchanged:: 2.0.2 Mask functions that take positions or offsets now + support :class:`pygame.math.Vector2` arguments. + + +.. function:: from_surface + + | :sl:`Creates a Mask from the given surface` + | :sg:`from_surface(surface) -> Mask` + | :sg:`from_surface(surface, threshold=127) -> Mask` + + Creates a :class:`Mask` object from the given surface by setting all the + opaque pixels and not setting the transparent pixels. + + If the surface uses a color-key, then it is used to decide which bits in + the resulting mask are set. All the pixels that are **not** equal to the + color-key are **set** and the pixels equal to the color-key are not set. + + If a color-key is not used, then the alpha value of each pixel is used to + decide which bits in the resulting mask are set. All the pixels that have an + alpha value **greater than** the ``threshold`` parameter are **set** and the + pixels with an alpha value less than or equal to the ``threshold`` are + not set. + + :param Surface surface: the surface to create the mask from + :param int threshold: (optional) the alpha threshold (default is 127) to + compare with each surface pixel's alpha value, if the ``surface`` is + color-keyed this parameter is ignored + + :returns: a newly created :class:`Mask` object from the given surface + :rtype: Mask + + .. note:: + This function is used to create the masks for + :func:`pygame.sprite.collide_mask`. + + .. ## pygame.mask.from_surface ## + +.. function:: from_threshold + + | :sl:`Creates a mask by thresholding Surfaces` + | :sg:`from_threshold(surface, color) -> Mask` + | :sg:`from_threshold(surface, color, threshold=(0, 0, 0, 255), othersurface=None, palette_colors=1) -> Mask` + + This is a more featureful method of getting a :class:`Mask` from a surface. + + If the optional ``othersurface`` is not used, all the pixels **within** the + ``threshold`` of the ``color`` parameter are **set** in the resulting mask. + + If the optional ``othersurface`` is used, every pixel in the first surface + that is **within** the ``threshold`` of the corresponding pixel in + ``othersurface`` is **set** in the resulting mask. + + :param Surface surface: the surface to create the mask from + :param color: color used to check if the surface's pixels are within the + given ``threshold`` range, this parameter is ignored if the optional + ``othersurface`` parameter is supplied + :type color: Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]] + :param threshold: (optional) the threshold range used to check the difference + between two colors (default is ``(0, 0, 0, 255)``) + :type threshold: Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]] + :param Surface othersurface: (optional) used to check whether the pixels of + the first surface are within the given ``threshold`` range of the pixels + from this surface (default is ``None``) + :param int palette_colors: (optional) indicates whether to use the palette + colors or not, a nonzero value causes the palette colors to be used and a + 0 causes them not to be used (default is 1) + + :returns: a newly created :class:`Mask` object from the given surface + :rtype: Mask + + .. ## pygame.mask.from_threshold ## + +.. class:: Mask + + | :sl:`pygame object for representing 2D bitmasks` + | :sg:`Mask(size=(width, height)) -> Mask` + | :sg:`Mask(size=(width, height), fill=False) -> Mask` + + A ``Mask`` object is used to represent a 2D bitmask. Each bit in + the mask represents a pixel. 1 is used to indicate a set bit and 0 is used + to indicate an unset bit. Set bits in a mask can be used to detect collisions + with other masks and their set bits. + + A filled mask has all of its bits set to 1, conversely an + unfilled/cleared/empty mask has all of its bits set to 0. Masks can be + created unfilled (default) or filled by using the ``fill`` parameter. Masks + can also be cleared or filled using the :func:`pygame.mask.Mask.clear()` and + :func:`pygame.mask.Mask.fill()` methods respectively. + + A mask's coordinates start in the top left corner at ``(0, 0)`` just like + :mod:`pygame.Surface`. Individual bits can be accessed using the + :func:`pygame.mask.Mask.get_at()` and :func:`pygame.mask.Mask.set_at()` + methods. + + .. _mask-offset-label: + + The methods :meth:`overlap`, :meth:`overlap_area`, :meth:`overlap_mask`, + :meth:`draw`, :meth:`erase`, and :meth:`convolve` use an offset parameter + to indicate the offset of another mask's top left corner from the calling + mask's top left corner. The calling mask's top left corner is considered to + be the origin ``(0, 0)``. Offsets are a sequence of two values + ``(x_offset, y_offset)``. Positive and negative offset values are supported. + + :: + + 0 to x (x_offset) + : : + 0 ..... +----:---------+ + to | : | + y .......... +-----------+ + (y_offset) | | othermask | + | +-----------+ + | calling_mask | + +--------------+ + + :param size: the dimensions of the mask (width and height) + :param bool fill: (optional) create an unfilled mask (default: ``False``) or + filled mask (``True``) + + :returns: a newly created :class:`Mask` object + :rtype: Mask + + .. versionchanged:: 2.0.0 + Shallow copy support added. The :class:`Mask` class supports the special + method ``__copy__()`` and shallow copying via ``copy.copy(mask)``. + .. versionchanged:: 2.0.0 Subclassing support added. The :class:`Mask` class + can be used as a base class. + .. versionchanged:: 1.9.5 Added support for keyword arguments. + .. versionchanged:: 1.9.5 Added the optional keyword parameter ``fill``. + .. versionchanged:: 1.9.5 Added support for masks with a width and/or a + height of 0. + + .. method:: copy + + | :sl:`Returns a new copy of the mask` + | :sg:`copy() -> Mask` + + :returns: a new copy of this mask, the new mask will have the same width, + height, and set/unset bits as the original + :rtype: Mask + + .. note:: + If a mask subclass needs to copy any instance specific attributes + then it should override the ``__copy__()`` method. The overridden + ``__copy__()`` method needs to call ``super().__copy__()`` and then + copy the required data as in the following example code. + + :: + + class SubMask(pygame.mask.Mask): + def __copy__(self): + new_mask = super().__copy__() + # Do any SubMask attribute copying here. + return new_mask + + .. versionadded:: 2.0.0 + + .. ## Mask.copy ## + + .. method:: get_size + + | :sl:`Returns the size of the mask` + | :sg:`get_size() -> (width, height)` + + :returns: the size of the mask, (width, height) + :rtype: tuple(int, int) + + .. ## Mask.get_size ## + + .. method:: get_rect + + | :sl:`Returns a Rect based on the size of the mask` + | :sg:`get_rect(\**kwargs) -> Rect` + + Returns a new :func:`pygame.Rect` object based on the size of this mask. + The rect's default position will be ``(0, 0)`` and its default width and + height will be the same as this mask's. The rect's attributes can be + altered via :func:`pygame.Rect` attribute keyword arguments/values passed + into this method. As an example, ``a_mask.get_rect(center=(10, 5))`` would + create a :func:`pygame.Rect` based on the mask's size centered at the + given position. + + :param dict kwargs: :func:`pygame.Rect` attribute keyword arguments/values + that will be applied to the rect + + :returns: a new :func:`pygame.Rect` object based on the size of this mask + with any :func:`pygame.Rect` attribute keyword arguments/values applied + to it + :rtype: Rect + + .. versionadded:: 2.0.0 + + .. ## Mask.get_rect ## + + .. method:: get_at + + | :sl:`Gets the bit at the given position` + | :sg:`get_at(pos) -> int` + + :param pos: the position of the bit to get (x, y) + + :returns: 1 if the bit is set, 0 if the bit is not set + :rtype: int + + :raises IndexError: if the position is outside of the mask's bounds + + .. ## Mask.get_at ## + + .. method:: set_at + + | :sl:`Sets the bit at the given position` + | :sg:`set_at(pos) -> None` + | :sg:`set_at(pos, value=1) -> None` + + :param pos: the position of the bit to set (x, y) + :param int value: any nonzero int will set the bit to 1, 0 will set the + bit to 0 (default is 1) + + :returns: ``None`` + :rtype: NoneType + + :raises IndexError: if the position is outside of the mask's bounds + + .. ## Mask.set_at ## + + .. method:: overlap + + | :sl:`Returns the point of intersection` + | :sg:`overlap(other, offset) -> (x, y)` + | :sg:`overlap(other, offset) -> None` + + Returns the first point of intersection encountered between this mask and + ``other``. A point of intersection is 2 overlapping set bits. + + The current algorithm searches the overlapping area in + ``sizeof(unsigned long int) * CHAR_BIT`` bit wide column blocks (the value + of ``sizeof(unsigned long int) * CHAR_BIT`` is platform dependent, for + clarity it will be referred to as ``W``). Starting at the top left corner + it checks bits 0 to ``W - 1`` of the first row (``(0, 0)`` to + ``(W - 1, 0)``) then continues to the next row (``(0, 1)`` to + ``(W - 1, 1)``). Once this entire column block is checked, it continues to + the next one (``W`` to ``2 * W - 1``). This is repeated until it finds a + point of intersection or the entire overlapping area is checked. + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: point of intersection or ``None`` if no intersection + :rtype: tuple(int, int) or NoneType + + .. ## Mask.overlap ## + + .. method:: overlap_area + + | :sl:`Returns the number of overlapping set bits` + | :sg:`overlap_area(other, offset) -> numbits` + + Returns the number of overlapping set bits between between this mask and + ``other``. + + This can be useful for collision detection. An approximate collision + normal can be found by calculating the gradient of the overlapping area + through the finite difference. + + :: + + dx = mask.overlap_area(other, (x + 1, y)) - mask.overlap_area(other, (x - 1, y)) + dy = mask.overlap_area(other, (x, y + 1)) - mask.overlap_area(other, (x, y - 1)) + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: the number of overlapping set bits + :rtype: int + + .. ## Mask.overlap_area ## + + .. method:: overlap_mask + + | :sl:`Returns a mask of the overlapping set bits` + | :sg:`overlap_mask(other, offset) -> Mask` + + Returns a :class:`Mask`, the same size as this mask, containing the + overlapping set bits between this mask and ``other``. + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: a newly created :class:`Mask` with the overlapping bits set + :rtype: Mask + + .. ## Mask.overlap_mask ## + + .. method:: fill + + | :sl:`Sets all bits to 1` + | :sg:`fill() -> None` + + Sets all bits in the mask to 1. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.fill ## + + .. method:: clear + + | :sl:`Sets all bits to 0` + | :sg:`clear() -> None` + + Sets all bits in the mask to 0. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.clear ## + + .. method:: invert + + | :sl:`Flips all the bits` + | :sg:`invert() -> None` + + Flips all of the bits in the mask. All the set bits are cleared to 0 and + all the unset bits are set to 1. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.invert ## + + .. method:: scale + + | :sl:`Resizes a mask` + | :sg:`scale((width, height)) -> Mask` + + Creates a new :class:`Mask` of the requested size with its bits scaled + from this mask. + + :param size: the width and height (size) of the mask to create + + :returns: a new :class:`Mask` object with its bits scaled from this mask + :rtype: Mask + + :raises ValueError: if ``width < 0`` or ``height < 0`` + + .. ## Mask.scale ## + + .. method:: draw + + | :sl:`Draws a mask onto another` + | :sg:`draw(other, offset) -> None` + + Performs a bitwise OR, drawing ``othermask`` onto this mask. + + :param Mask other: the mask to draw onto this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.draw ## + + .. method:: erase + + | :sl:`Erases a mask from another` + | :sg:`erase(other, offset) -> None` + + Erases (clears) all bits set in ``other`` from this mask. + + :param Mask other: the mask to erase from this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.erase ## + + .. method:: count + + | :sl:`Returns the number of set bits` + | :sg:`count() -> bits` + + :returns: the number of set bits in the mask + :rtype: int + + .. ## Mask.count ## + + .. method:: centroid + + | :sl:`Returns the centroid of the set bits` + | :sg:`centroid() -> (x, y)` + + Finds the centroid (the center mass of the set bits) for this mask. + + :returns: a coordinate tuple indicating the centroid of the mask, it will + return ``(0, 0)`` if the mask has no bits set + :rtype: tuple(int, int) + + .. ## Mask.centroid ## + + .. method:: angle + + | :sl:`Returns the orientation of the set bits` + | :sg:`angle() -> theta` + + Finds the approximate orientation (from -90 to 90 degrees) of the set bits + in the mask. This works best if performed on a mask with only one + connected component. + + :returns: the orientation of the set bits in the mask, it will return + ``0.0`` if the mask has no bits set + :rtype: float + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.angle ## + + .. method:: outline + + | :sl:`Returns a list of points outlining an object` + | :sg:`outline() -> [(x, y), ...]` + | :sg:`outline(every=1) -> [(x, y), ...]` + + Returns a list of points of the outline of the first connected component + encountered in the mask. To find a connected component, the mask is + searched per row (left to right) starting in the top left corner. + + The ``every`` optional parameter skips set bits in the outline. For + example, setting it to 10 would return a list of every 10th set bit in the + outline. + + :param int every: (optional) indicates the number of bits to skip over in + the outline (default is 1) + + :returns: a list of points outlining the first connected component + encountered, an empty list is returned if the mask has no bits set + :rtype: list[tuple(int, int)] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.outline ## + + .. method:: convolve + + | :sl:`Returns the convolution of this mask with another mask` + | :sg:`convolve(other) -> Mask` + | :sg:`convolve(other, output=None, offset=(0, 0)) -> Mask` + + Convolve this mask with the given ``other`` Mask. + + :param Mask other: mask to convolve this mask with + :param output: (optional) mask for output (default is ``None``) + :type output: Mask or NoneType + :param offset: the offset of ``other`` from this mask, (default is + ``(0, 0)``) + + :returns: a :class:`Mask` with the ``(i - offset[0], j - offset[1])`` bit + set, if shifting ``other`` (such that its bottom right corner is at + ``(i, j)``) causes it to overlap with this mask + + If an ``output`` Mask is specified, the output is drawn onto it and + it is returned. Otherwise a mask of size ``(MAX(0, width + other mask's + width - 1), MAX(0, height + other mask's height - 1))`` is created and + returned. + :rtype: Mask + + .. ## Mask.convolve ## + + .. method:: connected_component + + | :sl:`Returns a mask containing a connected component` + | :sg:`connected_component() -> Mask` + | :sg:`connected_component(pos) -> Mask` + + A connected component is a group (1 or more) of connected set bits + (orthogonally and diagonally). The SAUF algorithm, which checks 8 point + connectivity, is used to find a connected component in the mask. + + By default this method will return a :class:`Mask` containing the largest + connected component in the mask. Optionally, a bit coordinate can be + specified and the connected component containing it will be returned. If + the bit at the given location is not set, the returned :class:`Mask` will + be empty (no bits set). + + :param pos: (optional) selects the connected component that contains the + bit at this position + + :returns: a :class:`Mask` object (same size as this mask) with the largest + connected component from this mask, if this mask has no bits set then + an empty mask will be returned + + If the ``pos`` parameter is provided then the mask returned will have + the connected component that contains this position. An empty mask will + be returned if the ``pos`` parameter selects an unset bit. + :rtype: Mask + + :raises IndexError: if the optional ``pos`` parameter is outside of the + mask's bounds + + .. ## Mask.connected_component ## + + .. method:: connected_components + + | :sl:`Returns a list of masks of connected components` + | :sg:`connected_components() -> [Mask, ...]` + | :sg:`connected_components(minimum=0) -> [Mask, ...]` + + Provides a list containing a :class:`Mask` object for each connected + component. + + :param int minimum: (optional) indicates the minimum number of bits (to + filter out noise) per connected component (default is 0, which equates + to no minimum and is equivalent to setting it to 1, as a connected + component must have at least 1 bit set) + + :returns: a list containing a :class:`Mask` object for each connected + component, an empty list is returned if the mask has no bits set + :rtype: list[Mask] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.connected_components ## + + .. method:: get_bounding_rects + + | :sl:`Returns a list of bounding rects of connected components` + | :sg:`get_bounding_rects() -> [Rect, ...]` + + Provides a list containing a bounding rect for each connected component. + + :returns: a list containing a bounding rect for each connected component, + an empty list is returned if the mask has no bits set + :rtype: list[Rect] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.get_bounding_rects ## + + .. method:: to_surface + + | :sl:`Returns a surface with the mask drawn on it` + | :sg:`to_surface() -> Surface` + | :sg:`to_surface(surface=None, setsurface=None, unsetsurface=None, setcolor=(255, 255, 255, 255), unsetcolor=(0, 0, 0, 255), dest=(0, 0)) -> Surface` + + Draws this mask on the given surface. Set bits (bits set to 1) and unset + bits (bits set to 0) can be drawn onto a surface. + + :param surface: (optional) Surface to draw mask onto, if no surface is + provided one will be created (default is ``None``, which will cause a + surface with the parameters + ``Surface(size=mask.get_size(), flags=SRCALPHA, depth=32)`` to be + created, drawn on, and returned) + :type surface: Surface or None + :param setsurface: (optional) use this surface's color values to draw + set bits (default is ``None``), if this surface is smaller than the + mask any bits outside its bounds will use the ``setcolor`` value + :type setsurface: Surface or None + :param unsetsurface: (optional) use this surface's color values to draw + unset bits (default is ``None``), if this surface is smaller than the + mask any bits outside its bounds will use the ``unsetcolor`` value + :type unsetsurface: Surface or None + :param setcolor: (optional) color to draw set bits (default is + ``(255, 255, 255, 255)``, white), use ``None`` to skip drawing the set + bits, the ``setsurface`` parameter (if set) will takes precedence over + this parameter + :type setcolor: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) or None + :param unsetcolor: (optional) color to draw unset bits (default is + ``(0, 0, 0, 255)``, black), use ``None`` to skip drawing the unset + bits, the ``unsetsurface`` parameter (if set) will takes precedence + over this parameter + :type unsetcolor: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) or None + :param dest: (optional) surface destination of where to position the + topleft corner of the mask being drawn (default is ``(0, 0)``), if a + Rect is used as the ``dest`` parameter, its ``x`` and ``y`` attributes + will be used as the destination, **NOTE1:** rects with a negative width + or height value will not be normalized before using their ``x`` and + ``y`` values, **NOTE2:** this destination value is only used to + position the mask on the surface, it does not offset the ``setsurface`` + and ``unsetsurface`` from the mask, they are always aligned with the + mask (i.e. position ``(0, 0)`` on the mask always corresponds to + position ``(0, 0)`` on the ``setsurface`` and ``unsetsurface``) + :type dest: Rect or tuple(int, int) or list(int, int) or Vector2(int, int) + + :returns: the ``surface`` parameter (or a newly created surface if no + ``surface`` parameter was provided) with this mask drawn on it + :rtype: Surface + + :raises ValueError: if the ``setsurface`` parameter or ``unsetsurface`` + parameter does not have the same format (bytesize/bitsize/alpha) as + the ``surface`` parameter + + .. note :: + To skip drawing the set bits, both ``setsurface`` and ``setcolor`` must + be ``None``. The ``setsurface`` parameter defaults to ``None``, but + ``setcolor`` defaults to a color value and therefore must be set to + ``None``. + + .. note :: + To skip drawing the unset bits, both ``unsetsurface`` and + ``unsetcolor`` must be ``None``. The ``unsetsurface`` parameter + defaults to ``None``, but ``unsetcolor`` defaults to a color value and + therefore must be set to ``None``. + + .. versionadded:: 2.0.0 + + .. ## Mask.to_surface ## + + .. ## pygame.mask.Mask ## + +.. ## pygame.mask ## diff --git a/docs/ref/math.rst b/docs/ref/math.rst new file mode 100644 index 0000000..0f037d9 --- /dev/null +++ b/docs/ref/math.rst @@ -0,0 +1,1143 @@ +.. include:: common.txt + +:mod:`pygame.math` +================== + +.. module:: pygame.math + :synopsis: pygame module for vector classes + +| :sl:`pygame module for vector classes` + +The pygame math module currently provides Vector classes in two and three +dimensions, ``Vector2`` and ``Vector3`` respectively. + +They support the following numerical operations: ``vec + vec``, ``vec - vec``, +``vec * number``, ``number * vec``, ``vec / number``, ``vec // number``, ``vec += vec``, +``vec -= vec``, ``vec *= number``, ``vec /= number``, ``vec //= number``, ``round(vec, ndigits=0)``. + +All these operations will be performed elementwise. +In addition ``vec * vec`` will perform a scalar-product (a.k.a. dot-product). +If you want to multiply every element from vector v with every element from +vector w you can use the elementwise method: ``v.elementwise() * w`` + +The coordinates of a vector can be retrieved or set using attributes or +subscripts + +:: + + v = pygame.Vector3() + + v.x = 5 + v[1] = 2 * v.x + print(v[1]) # 10 + + v.x == v[0] + v.y == v[1] + v.z == v[2] + +Multiple coordinates can be set using slices or swizzling + +:: + + v = pygame.Vector2() + v.xy = 1, 2 + v[:] = 1, 2 + +.. versionadded:: 1.9.2pre +.. versionchanged:: 1.9.4 Removed experimental notice. +.. versionchanged:: 1.9.4 Allow scalar construction like GLSL Vector2(2) == Vector2(2.0, 2.0) +.. versionchanged:: 1.9.4 :mod:`pygame.math` import not required. More convenient ``pygame.Vector2`` and ``pygame.Vector3``. +.. versionchanged:: 2.2.0 `round` returns a new vector with components rounded to the specified digits. + +.. function:: clamp + + | :sl:`returns value clamped to min and max.` + | :sg:`clamp(value, min, max) -> float` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave clamp feedback with authors `_ + + Clamps a numeric ``value`` so that it's no lower than ``min``, and no higher + than ``max``. + + .. versionadded:: 2.1.3 + + .. ## math.clamp ## + +.. function:: lerp + + | :sl:`interpolates between two values by a weight.` + | :sg:`lerp(a, b, weight) -> float` + + Linearly interpolates between ``a`` and ``b`` by ``weight`` using the formula ``a + (b-a) * weight``. + + If ``weight`` is ``0.5``, ``lerp`` will return the value half-way between ``a`` + and ``b``. When ``a = 10`` and ``b = 20``, ``lerp(a, b, 0.5)`` will return ``15``. You + can think of weight as the percentage of interpolation from ``a`` to ``b``, ``0.0`` + being 0% and ``1.0`` being 100%. + + ``lerp`` can be used for many things. You could rotate a sprite by a weight with + ``angle = lerp(0, 360, weight)``. You could even scale an enemy's attack value + based on the level you're playing: + + :: + + FINAL_LEVEL = 10 + current_level = 2 + + attack = lerp(10, 50, current_level/MAX_LEVEL) # 18 + + If you're on level 0, ``attack`` will be ``10``, if you're on level 10, + ``attack`` will be ``50``. If you're on level 5, the + result of ``current_level/MAX_LEVEL`` will be ``0.5`` + which represents 50%, therefore ``attack`` will be ``30``, which is the midpoint of ``10`` and ``50``. + + Raises a ValueError if ``weight`` is outside the range of ``[0, 1]``. + + .. versionadded:: 2.1.3 + + .. ## math.lerp ## + +.. class:: Vector2 + + | :sl:`a 2-Dimensional Vector` + | :sg:`Vector2() -> Vector2(0, 0)` + | :sg:`Vector2(int) -> Vector2` + | :sg:`Vector2(float) -> Vector2` + | :sg:`Vector2(Vector2) -> Vector2` + | :sg:`Vector2(x, y) -> Vector2` + | :sg:`Vector2((x, y)) -> Vector2` + + Some general information about the ``Vector2`` class. + + .. versionchanged:: 2.1.3 + Inherited methods of vector subclasses now correctly return an instance of the + subclass instead of the superclass + + .. method:: dot + + | :sl:`calculates the dot- or scalar-product with the other vector` + | :sg:`dot(Vector2) -> float` + + .. ## Vector2.dot ## + + .. method:: cross + + | :sl:`calculates the cross- or vector-product` + | :sg:`cross(Vector2) -> float` + + calculates the third component of the cross-product. + + .. ## Vector2.cross ## + + .. method:: magnitude + + | :sl:`returns the Euclidean magnitude of the vector.` + | :sg:`magnitude() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2)`` + + .. ## Vector2.magnitude ## + + .. method:: magnitude_squared + + | :sl:`returns the squared magnitude of the vector.` + | :sg:`magnitude_squared() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude_squared() == vec.x**2 + vec.y**2``. This + is faster than ``vec.magnitude()`` because it avoids the square root. + + .. ## Vector2.magnitude_squared ## + + .. method:: length + + | :sl:`returns the Euclidean length of the vector.` + | :sg:`length() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: ``vec.length() == math.sqrt(vec.x**2 + vec.y**2)`` + + .. ## Vector2.length ## + + .. method:: length_squared + + | :sl:`returns the squared Euclidean length of the vector.` + | :sg:`length_squared() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: ``vec.length_squared() == vec.x**2 + vec.y**2``. + This is faster than ``vec.length()`` because it avoids the square root. + + .. ## Vector2.length_squared ## + + .. method:: normalize + + | :sl:`returns a vector with the same direction but length 1.` + | :sg:`normalize() -> Vector2` + + Returns a new vector that has ``length`` equal to ``1`` and the same + direction as self. + + .. ## Vector2.normalize ## + + .. method:: normalize_ip + + | :sl:`normalizes the vector in place so that its length is 1.` + | :sg:`normalize_ip() -> None` + + Normalizes the vector so that it has ``length`` equal to ``1``. + The direction of the vector is not changed. + + .. ## Vector2.normalize_ip ## + + .. method:: is_normalized + + | :sl:`tests if the vector is normalized i.e. has length == 1.` + | :sg:`is_normalized() -> Bool` + + Returns True if the vector has ``length`` equal to ``1``. Otherwise + it returns ``False``. + + .. ## Vector2.is_normalized ## + + .. method:: scale_to_length + + | :sl:`scales the vector to a given length.` + | :sg:`scale_to_length(float) -> None` + + Scales the vector so that it has the given length. The direction of the + vector is not changed. You can also scale to length ``0``. If the vector + is the zero vector (i.e. has length ``0`` thus no direction) a + ``ValueError`` is raised. + + .. ## Vector2.scale_to_length ## + + .. method:: reflect + + | :sl:`returns a vector reflected of a given normal.` + | :sg:`reflect(Vector2) -> Vector2` + + Returns a new vector that points in the direction as if self would bounce + of a surface characterized by the given surface normal. The length of the + new vector is the same as self's. + + .. ## Vector2.reflect ## + + .. method:: reflect_ip + + | :sl:`reflect the vector of a given normal in place.` + | :sg:`reflect_ip(Vector2) -> None` + + Changes the direction of self as if it would have been reflected of a + surface with the given surface normal. + + .. ## Vector2.reflect_ip ## + + .. method:: distance_to + + | :sl:`calculates the Euclidean distance to a given vector.` + | :sg:`distance_to(Vector2) -> float` + + .. ## Vector2.distance_to ## + + .. method:: distance_squared_to + + | :sl:`calculates the squared Euclidean distance to a given vector.` + | :sg:`distance_squared_to(Vector2) -> float` + + .. ## Vector2.distance_squared_to ## + + .. method:: move_towards + + | :sl:`returns a vector moved toward the target by a given distance.` + | :sg:`move_towards(Vector2, float) -> Vector2` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave move_towards feedback with authors `_ + + Returns a Vector which is moved towards the given Vector by a given + distance and does not overshoot past its target Vector. + The first parameter determines the target Vector, while the second + parameter determines the delta distance. If the distance is in the + negatives, then it will move away from the target Vector. + + .. versionadded:: 2.1.3 + + .. ## Vector2.move_towards ## + + .. method:: move_towards_ip + + | :sl:`moves the vector toward its target at a given distance.` + | :sg:`move_towards_ip(Vector2, float) -> None` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave move_towards_ip feedback with authors `_ + + Moves itself toward the given Vector at a given distance and does not + overshoot past its target Vector. + The first parameter determines the target Vector, while the second + parameter determines the delta distance. If the distance is in the + negatives, then it will move away from the target Vector. + + .. versionadded:: 2.1.3 + + .. ## Vector2.move_towards_ip ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given vector.` + | :sg:`lerp(Vector2, float) -> Vector2` + + Returns a Vector which is a linear interpolation between self and the + given Vector. The second parameter determines how far between self and + other the result is going to be. It must be a value between ``0`` and ``1`` + where ``0`` means self and ``1`` means other will be returned. + + .. ## Vector2.lerp ## + + .. method:: slerp + + | :sl:`returns a spherical interpolation to the given vector.` + | :sg:`slerp(Vector2, float) -> Vector2` + + Calculates the spherical interpolation from self to the given Vector. The + second argument - often called t - must be in the range ``[-1, 1]``. It + parametrizes where - in between the two vectors - the result should be. + If a negative value is given the interpolation will not take the + complement of the shortest path. + + .. ## Vector2.slerp ## + + .. method:: elementwise + + | :sl:`The next operation will be performed elementwise.` + | :sg:`elementwise() -> VectorElementwiseProxy` + + Applies the following operation to each element of the vector. + + .. ## Vector2.elementwise ## + + .. method:: rotate + + | :sl:`rotates a vector by a given angle in degrees.` + | :sg:`rotate(angle) -> Vector2` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector2.rotate ## + + .. method:: rotate_rad + + | :sl:`rotates a vector by a given angle in radians.` + | :sg:`rotate_rad(angle) -> Vector2` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector2.rotate_rad ## + + .. method:: rotate_ip + + | :sl:`rotates the vector by a given angle in degrees in place.` + | :sg:`rotate_ip(angle) -> None` + + Rotates the vector counterclockwise by the given angle in degrees. The + length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector2.rotate_ip ## + + .. method:: rotate_ip_rad + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector2.rotate_rad_ip ## + + .. method:: rotate_rad_ip + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_rad_ip(angle) -> None` + + Rotates the vector counterclockwise by the given angle in radians. The + length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector2.rotate_rad_ip ## + + .. method:: angle_to + + | :sl:`calculates the angle to a given vector in degrees.` + | :sg:`angle_to(Vector2) -> float` + + Returns the angle from self to the passed ``Vector2`` that would rotate self + to be aligned with the passed ``Vector2`` without crossing over the negative + x-axis. + + .. figure:: code_examples/angle_to.png + :alt: angle_to image + + Example demonstrating the angle returned + + .. ## Vector2.angle_to ## + + .. method:: as_polar + + | :sl:`returns a tuple with radial distance and azimuthal angle.` + | :sg:`as_polar() -> (r, phi)` + + Returns a tuple ``(r, phi)`` where r is the radial distance, and phi + is the azimuthal angle. + + .. ## Vector2.as_polar ## + + .. method:: from_polar + + | :sl:`Creates a Vector2(x, y) or sets x and y from a polar coordinates tuple.` + | :sg:`Vector2.from_polar((r, phi)) -> Vector2` + | :sg:`Vector2().from_polar((r, phi)) -> None` + + If used from the class creates a Vector2(x,y), else sets x and y. + The values of x and y are defined from a tuple ``(r, phi)`` where r + is the radial distance, and phi is the azimuthal angle. + + .. ## Vector2.from_polar ## + + .. method:: project + + | :sl:`projects a vector onto another.` + | :sg:`project(Vector2) -> Vector2` + + Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). + For a more detailed explanation see `Wikipedia `_. + + .. versionadded:: 2.0.2 + + .. ## Vector2.project ## + + + .. method:: copy + + | :sl:`Returns a copy of itself.` + | :sg:`copy() -> Vector2` + + Returns a new Vector2 having the same dimensions. + + .. versionadded:: 2.1.1 + + .. ## Vector2.copy ## + + + .. method:: clamp_magnitude + + | :sl:`Returns a copy of a vector with the magnitude clamped between max_length and min_length.` + | :sg:`clamp_magnitude(max_length) -> Vector2` + | :sg:`clamp_magnitude(min_length, max_length) -> Vector2` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave clamp_magnitude feedback with authors `_ + + Returns a new copy of a vector with the magnitude clamped between + ``max_length`` and ``min_length``. If only one argument is passed, it is + taken to be the ``max_length`` + + This function raises ``ValueError`` if ``min_length`` is greater than + ``max_length``, or if either of these values are negative. + + .. versionadded:: 2.1.3 + + .. ## Vector2.clamp_magnitude ## + + + .. method:: clamp_magnitude_ip + + | :sl:`Clamps the vector's magnitude between max_length and min_length` + | :sg:`clamp_magnitude_ip(max_length) -> None` + | :sg:`clamp_magnitude_ip(min_length, max_length) -> None` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave clamp_magnitude_ip feedback with authors `_ + + Clamps the vector's magnitude between ``max_length`` and ``min_length``. + If only one argument is passed, it is taken to be the ``max_length`` + + This function raises ``ValueError`` if ``min_length`` is greater than + ``max_length``, or if either of these values are negative. + + .. versionadded:: 2.1.3 + + .. ## Vector2.clamp_magnitude_ip ## + + + .. method:: update + + | :sl:`Sets the coordinates of the vector.` + | :sg:`update() -> None` + | :sg:`update(int) -> None` + | :sg:`update(float) -> None` + | :sg:`update(Vector2) -> None` + | :sg:`update(x, y) -> None` + | :sg:`update((x, y)) -> None` + + Sets coordinates x and y in place. + + .. versionadded:: 1.9.5 + + .. ## Vector2.update ## + + + .. attribute:: epsilon + + | :sl:`Determines the tolerance of vector calculations.` + + Both Vector classes have a value named ``epsilon`` that defaults to ``1e-6``. + This value acts as a numerical margin in various methods to account for floating point + arithmetic errors. Specifically, ``epsilon`` is used in the following places: + + * comparing Vectors (``==`` and ``!=``) + * the ``is_normalized`` method (if the square of the length is within ``epsilon`` of 1, it's normalized) + * slerping (a Vector with a length of ``> True + print(v == u) # >> False + + You'll probably never have to change ``epsilon`` from the default value, but in rare situations you might + find that either the margin is too large or too small, in which case changing ``epsilon`` slightly + might help you out. + + + .. ## pygame.math.Vector2 ## + +.. class:: Vector3 + + | :sl:`a 3-Dimensional Vector` + | :sg:`Vector3() -> Vector3(0, 0, 0)` + | :sg:`Vector3(int) -> Vector3` + | :sg:`Vector3(float) -> Vector3` + | :sg:`Vector3(Vector3) -> Vector3` + | :sg:`Vector3(x, y, z) -> Vector3` + | :sg:`Vector3((x, y, z)) -> Vector3` + + Some general information about the Vector3 class. + + .. versionchanged:: 2.1.3 + Inherited methods of vector subclasses now correctly return an instance of the + subclass instead of the superclass + + .. method:: dot + + | :sl:`calculates the dot- or scalar-product with the other vector` + | :sg:`dot(Vector3) -> float` + + .. ## Vector3.dot ## + + .. method:: cross + + | :sl:`calculates the cross- or vector-product` + | :sg:`cross(Vector3) -> Vector3` + + calculates the cross-product. + + .. ## Vector3.cross ## + + .. method:: magnitude + + | :sl:`returns the Euclidean magnitude of the vector.` + | :sg:`magnitude() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)`` + + .. ## Vector3.magnitude ## + + .. method:: magnitude_squared + + | :sl:`returns the squared Euclidean magnitude of the vector.` + | :sg:`magnitude_squared() -> float` + + calculates the magnitude of the vector which follows from the + theorem: + ``vec.magnitude_squared() == vec.x**2 + vec.y**2 + vec.z**2``. + This is faster than ``vec.magnitude()`` because it avoids the + square root. + + .. ## Vector3.magnitude_squared ## + + .. method:: length + + | :sl:`returns the Euclidean length of the vector.` + | :sg:`length() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: + ``vec.length() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)`` + + .. ## Vector3.length ## + + .. method:: length_squared + + | :sl:`returns the squared Euclidean length of the vector.` + | :sg:`length_squared() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: + ``vec.length_squared() == vec.x**2 + vec.y**2 + vec.z**2``. + This is faster than ``vec.length()`` because it avoids the square root. + + .. ## Vector3.length_squared ## + + .. method:: normalize + + | :sl:`returns a vector with the same direction but length 1.` + | :sg:`normalize() -> Vector3` + + Returns a new vector that has ``length`` equal to ``1`` and the same + direction as self. + + .. ## Vector3.normalize ## + + .. method:: normalize_ip + + | :sl:`normalizes the vector in place so that its length is 1.` + | :sg:`normalize_ip() -> None` + + Normalizes the vector so that it has ``length`` equal to ``1``. The + direction of the vector is not changed. + + .. ## Vector3.normalize_ip ## + + .. method:: is_normalized + + | :sl:`tests if the vector is normalized i.e. has length == 1.` + | :sg:`is_normalized() -> Bool` + + Returns True if the vector has ``length`` equal to ``1``. Otherwise it + returns ``False``. + + .. ## Vector3.is_normalized ## + + .. method:: scale_to_length + + | :sl:`scales the vector to a given length.` + | :sg:`scale_to_length(float) -> None` + + Scales the vector so that it has the given length. The direction of the + vector is not changed. You can also scale to length ``0``. If the vector + is the zero vector (i.e. has length ``0`` thus no direction) a + ``ValueError`` is raised. + + .. ## Vector3.scale_to_length ## + + .. method:: reflect + + | :sl:`returns a vector reflected of a given normal.` + | :sg:`reflect(Vector3) -> Vector3` + + Returns a new vector that points in the direction as if self would bounce + of a surface characterized by the given surface normal. The length of the + new vector is the same as self's. + + .. ## Vector3.reflect ## + + .. method:: reflect_ip + + | :sl:`reflect the vector of a given normal in place.` + | :sg:`reflect_ip(Vector3) -> None` + + Changes the direction of self as if it would have been reflected of a + surface with the given surface normal. + + .. ## Vector3.reflect_ip ## + + .. method:: distance_to + + | :sl:`calculates the Euclidean distance to a given vector.` + | :sg:`distance_to(Vector3) -> float` + + .. ## Vector3.distance_to ## + + .. method:: distance_squared_to + + | :sl:`calculates the squared Euclidean distance to a given vector.` + | :sg:`distance_squared_to(Vector3) -> float` + + .. ## Vector3.distance_squared_to ## + + .. method:: move_towards + + | :sl:`returns a vector moved toward the target by a given distance.` + | :sg:`move_towards(Vector3, float) -> Vector3` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave move_towards feedback with authors `_ + + Returns a Vector which is moved towards the given Vector by a given + distance and does not overshoot past its target Vector. + The first parameter determines the target Vector, while the second + parameter determines the delta distance. If the distance is in the + negatives, then it will move away from the target Vector. + + .. versionadded:: 2.1.3 + + .. ## Vector3.move_towards ## + + .. method:: move_towards_ip + + | :sl:`moves the vector toward its target at a given distance.` + | :sg:`move_towards_ip(Vector3, float) -> None` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave move_towards_ip feedback with authors `_ + + Moves itself toward the given Vector at a given distance and does not + overshoot past its target Vector. + The first parameter determines the target Vector, while the second + parameter determines the delta distance. If the distance is in the + negatives, then it will move away from the target Vector. + + .. versionadded:: 2.1.3 + + .. ## Vector3.move_towards_ip ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given vector.` + | :sg:`lerp(Vector3, float) -> Vector3` + + Returns a Vector which is a linear interpolation between self and the + given Vector. The second parameter determines how far between self an + other the result is going to be. It must be a value between ``0`` and + ``1``, where ``0`` means self and ``1`` means other will be returned. + + .. ## Vector3.lerp ## + + .. method:: slerp + + | :sl:`returns a spherical interpolation to the given vector.` + | :sg:`slerp(Vector3, float) -> Vector3` + + Calculates the spherical interpolation from self to the given Vector. The + second argument - often called t - must be in the range ``[-1, 1]``. It + parametrizes where - in between the two vectors - the result should be. + If a negative value is given the interpolation will not take the + complement of the shortest path. + + .. ## Vector3.slerp ## + + .. method:: elementwise + + | :sl:`The next operation will be performed elementwise.` + | :sg:`elementwise() -> VectorElementwiseProxy` + + Applies the following operation to each element of the vector. + + .. ## Vector3.elementwise ## + + .. method:: rotate + + | :sl:`rotates a vector by a given angle in degrees.` + | :sg:`rotate(angle, Vector3) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in degrees around the given axis. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate ## + + .. method:: rotate_rad + + | :sl:`rotates a vector by a given angle in radians.` + | :sg:`rotate_rad(angle, Vector3) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in radians around the given axis. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_rad ## + + .. method:: rotate_ip + + | :sl:`rotates the vector by a given angle in degrees in place.` + | :sg:`rotate_ip(angle, Vector3) -> None` + + Rotates the vector counterclockwise around the given axis by the given + angle in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_ip ## + + .. method:: rotate_ip_rad + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_ip_rad(angle, Vector3) -> None` + + DEPRECATED: Use rotate_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_ip_rad ## + + .. method:: rotate_rad_ip + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_rad_ip(angle, Vector3) -> None` + + Rotates the vector counterclockwise around the given axis by the given + angle in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_rad_ip ## + + .. method:: rotate_x + + | :sl:`rotates a vector around the x-axis by the angle in degrees.` + | :sg:`rotate_x(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the x-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_x ## + + .. method:: rotate_x_rad + + | :sl:`rotates a vector around the x-axis by the angle in radians.` + | :sg:`rotate_x_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the x-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_x_rad ## + + .. method:: rotate_x_ip + + | :sl:`rotates the vector around the x-axis by the angle in degrees in place.` + | :sg:`rotate_x_ip(angle) -> None` + + Rotates the vector counterclockwise around the x-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_x_ip ## + + .. method:: rotate_x_ip_rad + + | :sl:`rotates the vector around the x-axis by the angle in radians in place.` + | :sg:`rotate_x_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_x_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_x_ip_rad ## + + .. method:: rotate_x_rad_ip + + | :sl:`rotates the vector around the x-axis by the angle in radians in place.` + | :sg:`rotate_x_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the x-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_x_rad_ip ## + + .. method:: rotate_y + + | :sl:`rotates a vector around the y-axis by the angle in degrees.` + | :sg:`rotate_y(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the y-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_y ## + + .. method:: rotate_y_rad + + | :sl:`rotates a vector around the y-axis by the angle in radians.` + | :sg:`rotate_y_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the y-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_y_rad ## + + .. method:: rotate_y_ip + + | :sl:`rotates the vector around the y-axis by the angle in degrees in place.` + | :sg:`rotate_y_ip(angle) -> None` + + Rotates the vector counterclockwise around the y-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_y_ip ## + + .. method:: rotate_y_ip_rad + + | :sl:`rotates the vector around the y-axis by the angle in radians in place.` + | :sg:`rotate_y_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_y_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_y_ip_rad ## + + .. method:: rotate_y_rad_ip + + | :sl:`rotates the vector around the y-axis by the angle in radians in place.` + | :sg:`rotate_y_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the y-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_y_rad_ip ## + + .. method:: rotate_z + + | :sl:`rotates a vector around the z-axis by the angle in degrees.` + | :sg:`rotate_z(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the z-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_z ## + + .. method:: rotate_z_rad + + | :sl:`rotates a vector around the z-axis by the angle in radians.` + | :sg:`rotate_z_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the z-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_z_rad ## + + .. method:: rotate_z_ip + + | :sl:`rotates the vector around the z-axis by the angle in degrees in place.` + | :sg:`rotate_z_ip(angle) -> None` + + Rotates the vector counterclockwise around the z-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_z_ip ## + + .. method:: rotate_z_ip_rad + + | :sl:`rotates the vector around the z-axis by the angle in radians in place.` + | :sg:`rotate_z_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_z_rad_ip() instead. + + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_z_ip_rad ## + + .. method:: rotate_z_rad_ip + + | :sl:`rotates the vector around the z-axis by the angle in radians in place.` + | :sg:`rotate_z_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the z-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_z_rad_ip ## + + .. method:: angle_to + + | :sl:`calculates the angle to a given vector in degrees.` + | :sg:`angle_to(Vector3) -> float` + + Returns the angle between self and the given vector. + + .. ## Vector3.angle_to ## + + .. method:: as_spherical + + | :sl:`returns a tuple with radial distance, inclination and azimuthal angle.` + | :sg:`as_spherical() -> (r, theta, phi)` + + Returns a tuple ``(r, theta, phi)`` where r is the radial distance, theta is + the inclination angle and phi is the azimuthal angle. + + .. ## Vector3.as_spherical ## + + .. method:: from_spherical + + | :sl:`Creates a Vector3(x, y, z) or sets x, y and z from a spherical coordinates 3-tuple.` + | :sg:`Vector3.from_spherical((r, theta, phi)) -> Vector3` + | :sg:`Vector3().from_spherical((r, theta, phi)) -> None` + + If used from the class creates a Vector3(x, y, z), else sets x, y, and z. + The values of x, y, and z are from a tuple ``(r, theta, phi)`` where r is the radial + distance, theta is the inclination angle and phi is the azimuthal angle. + + .. ## Vector3.from_spherical ## + + .. method:: project + + | :sl:`projects a vector onto another.` + | :sg:`project(Vector3) -> Vector3` + + Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). + For a more detailed explanation see `Wikipedia `_. + + .. versionadded:: 2.0.2 + + .. ## Vector3.project ## + + .. method:: copy + + | :sl:`Returns a copy of itself.` + | :sg:`copy() -> Vector3` + + Returns a new Vector3 having the same dimensions. + + .. versionadded:: 2.1.1 + + .. ## Vector3.copy ## + + + .. method:: clamp_magnitude + + | :sl:`Returns a copy of a vector with the magnitude clamped between max_length and min_length.` + | :sg:`clamp_magnitude(max_length) -> Vector3` + | :sg:`clamp_magnitude(min_length, max_length) -> Vector3` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave clamp_magnitude feedback with authors `_ + + Returns a new copy of a vector with the magnitude clamped between + ``max_length`` and ``min_length``. If only one argument is passed, it is + taken to be the ``max_length`` + + This function raises ``ValueError`` if ``min_length`` is greater than + ``max_length``, or if either of these values are negative. + + .. versionadded:: 2.1.3 + + .. ## Vector3.clamp_magnitude ## + + + .. method:: clamp_magnitude_ip + + | :sl:`Clamps the vector's magnitude between max_length and min_length` + | :sg:`clamp_magnitude_ip(max_length) -> None` + | :sg:`clamp_magnitude_ip(min_length, max_length) -> None` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave clamp_magnitude_ip feedback with authors `_ + + Clamps the vector's magnitude between ``max_length`` and ``min_length``. + If only one argument is passed, it is taken to be the ``max_length`` + + This function raises ``ValueError`` if ``min_length`` is greater than + ``max_length``, or if either of these values are negative. + + .. versionadded:: 2.1.3 + + .. ## Vector3.clamp_magnitude_ip ## + + .. method:: update + + | :sl:`Sets the coordinates of the vector.` + | :sg:`update() -> None` + | :sg:`update(int) -> None` + | :sg:`update(float) -> None` + | :sg:`update(Vector3) -> None` + | :sg:`update(x, y, z) -> None` + | :sg:`update((x, y, z)) -> None` + + Sets coordinates x, y, and z in place. + + .. versionadded:: 1.9.5 + + .. ## Vector3.update ## + + .. attribute:: epsilon + + | :sl:`Determines the tolerance of vector calculations.` + + With lengths within this number, vectors are considered equal. For more information see :attr:`pygame.math.Vector2.epsilon` + + .. ## ## + + .. ## pygame.math.Vector3 ## + +.. ## pygame.math ## diff --git a/docs/ref/midi.rst b/docs/ref/midi.rst new file mode 100644 index 0000000..edc9f25 --- /dev/null +++ b/docs/ref/midi.rst @@ -0,0 +1,484 @@ +.. include:: common.txt + +:mod:`pygame.midi` +================== + +.. module:: pygame.midi + :synopsis: pygame module for interacting with midi input and output. + +| :sl:`pygame module for interacting with midi input and output.` + +.. versionadded:: 1.9.0 + +The midi module can send output to midi devices and get input from midi +devices. It can also list midi devices on the system. + +The midi module supports real and virtual midi devices. + +It uses the portmidi library. Is portable to which ever platforms portmidi +supports (currently Windows, Mac OS X, and Linux). + +This uses pyportmidi for now, but may use its own bindings at some point in the +future. The pyportmidi bindings are included with pygame. + +| + +.. versionadded:: 2.0.0 + +These are pygame events (:mod:`pygame.event`) reserved for midi use. The +``MIDIIN`` event is used by :func:`pygame.midi.midis2events` when converting +midi events to pygame events. + +:: + + MIDIIN + MIDIOUT + +| + +.. function:: init + + | :sl:`initialize the midi module` + | :sg:`init() -> None` + + Initializes the :mod:`pygame.midi` module. Must be called before using the + :mod:`pygame.midi` module. + + It is safe to call this more than once. + + .. ## pygame.midi.init ## + +.. function:: quit + + | :sl:`uninitialize the midi module` + | :sg:`quit() -> None` + + Uninitializes the :mod:`pygame.midi` module. If :func:`pygame.midi.init` was + called to initialize the :mod:`pygame.midi` module, then this function will + be called automatically when your program exits. + + It is safe to call this function more than once. + + .. ## pygame.midi.quit ## + +.. function:: get_init + + | :sl:`returns True if the midi module is currently initialized` + | :sg:`get_init() -> bool` + + Gets the initialization state of the :mod:`pygame.midi` module. + + :returns: ``True`` if the :mod:`pygame.midi` module is currently initialized. + :rtype: bool + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.get_init ## + +.. class:: Input + + | :sl:`Input is used to get midi input from midi devices.` + | :sg:`Input(device_id) -> None` + | :sg:`Input(device_id, buffer_size) -> None` + + :param int device_id: midi device id + :param int buffer_size: (optional) the number of input events to be buffered + + .. method:: close + + | :sl:`closes a midi stream, flushing any pending buffers.` + | :sg:`close() -> None` + + PortMidi attempts to close open streams when the application exits. + + .. note:: This is particularly difficult under Windows. + + .. ## Input.close ## + + .. method:: poll + + | :sl:`returns True if there's data, or False if not.` + | :sg:`poll() -> bool` + + Used to indicate if any data exists. + + :returns: ``True`` if there is data, ``False`` otherwise + :rtype: bool + + :raises MidiException: on error + + .. ## Input.poll ## + + .. method:: read + + | :sl:`reads num_events midi events from the buffer.` + | :sg:`read(num_events) -> midi_event_list` + + Reads from the input buffer and gives back midi events. + + :param int num_events: number of input events to read + + :returns: the format for midi_event_list is + ``[[[status, data1, data2, data3], timestamp], ...]`` + :rtype: list + + .. ## Input.read ## + + .. ## pygame.midi.Input ## + +.. class:: Output + + | :sl:`Output is used to send midi to an output device` + | :sg:`Output(device_id) -> None` + | :sg:`Output(device_id, latency=0) -> None` + | :sg:`Output(device_id, buffer_size=256) -> None` + | :sg:`Output(device_id, latency, buffer_size) -> None` + + The ``buffer_size`` specifies the number of output events to be buffered + waiting for output. In some cases (see below) PortMidi does not buffer + output at all and merely passes data to a lower-level API, in which case + buffersize is ignored. + + ``latency`` is the delay in milliseconds applied to timestamps to determine + when the output should actually occur. If ``latency`` is <<0, 0 is assumed. + + If ``latency`` is zero, timestamps are ignored and all output is delivered + immediately. If ``latency`` is greater than zero, output is delayed until the + message timestamp plus the ``latency``. In some cases, PortMidi can obtain + better timing than your application by passing timestamps along to the + device driver or hardware. Latency may also help you to synchronize midi + data to audio data by matching midi latency to the audio buffer latency. + + .. note:: + Time is measured relative to the time source indicated by time_proc. + Timestamps are absolute, not relative delays or offsets. + + .. method:: abort + + | :sl:`terminates outgoing messages immediately` + | :sg:`abort() -> None` + + The caller should immediately close the output port; this call may result + in transmission of a partial midi message. There is no abort for Midi + input because the user can simply ignore messages in the buffer and close + an input device at any time. + + .. ## Output.abort ## + + .. method:: close + + | :sl:`closes a midi stream, flushing any pending buffers.` + | :sg:`close() -> None` + + PortMidi attempts to close open streams when the application exits. + + .. note:: This is particularly difficult under Windows. + + .. ## Output.close ## + + .. method:: note_off + + | :sl:`turns a midi note off (note must be on)` + | :sg:`note_off(note, velocity=None, channel=0) -> None` + + Turn a note off in the output stream. The note must already be on for + this to work correctly. + + .. ## Output.note_off ## + + .. method:: note_on + + | :sl:`turns a midi note on (note must be off)` + | :sg:`note_on(note, velocity=None, channel=0) -> None` + + Turn a note on in the output stream. The note must already be off for + this to work correctly. + + .. ## Output.note_on ## + + .. method:: set_instrument + + | :sl:`select an instrument, with a value between 0 and 127` + | :sg:`set_instrument(instrument_id, channel=0) -> None` + + Select an instrument. + + .. ## Output.set_instrument ## + + .. method:: pitch_bend + + | :sl:`modify the pitch of a channel.` + | :sg:`set_instrument(value=0, channel=0) -> None` + + Adjust the pitch of a channel. The value is a signed integer + from -8192 to +8191. For example, 0 means "no change", +4096 is + typically a semitone higher, and -8192 is 1 whole tone lower (though + the musical range corresponding to the pitch bend range can also be + changed in some synthesizers). + + If no value is given, the pitch bend is returned to "no change". + + .. versionadded:: 1.9.4 + + .. method:: write + + | :sl:`writes a list of midi data to the Output` + | :sg:`write(data) -> None` + + Writes series of MIDI information in the form of a list. + + :param list data: data to write, the expected format is + ``[[[status, data1=0, data2=0, ...], timestamp], ...]`` + with the ``data#`` fields being optional + + :raises IndexError: if more than 1024 elements in the data list + + Example: + :: + + # Program change at time 20000 and 500ms later send note 65 with + # velocity 100. + write([[[0xc0, 0, 0], 20000], [[0x90, 60, 100], 20500]]) + + .. note:: + - Timestamps will be ignored if latency = 0 + - To get a note to play immediately, send MIDI info with timestamp + read from function Time + - Optional data fields: ``write([[[0xc0, 0, 0], 20000]])`` is + equivalent to ``write([[[0xc0], 20000]])`` + + .. ## Output.write ## + + .. method:: write_short + + | :sl:`writes up to 3 bytes of midi data to the Output` + | :sg:`write_short(status) -> None` + | :sg:`write_short(status, data1=0, data2=0) -> None` + + Output MIDI information of 3 bytes or less. The ``data`` fields are + optional and assumed to be 0 if omitted. + + Examples of status byte values: + :: + + 0xc0 # program change + 0x90 # note on + # etc. + + Example: + :: + + # note 65 on with velocity 100 + write_short(0x90, 65, 100) + + .. ## Output.write_short ## + + .. method:: write_sys_ex + + | :sl:`writes a timestamped system-exclusive midi message.` + | :sg:`write_sys_ex(when, msg) -> None` + + Writes a timestamped system-exclusive midi message. + + :param msg: midi message + :type msg: list[int] or str + :param when: timestamp in milliseconds + + Example: + :: + + midi_output.write_sys_ex(0, '\xF0\x7D\x10\x11\x12\x13\xF7') + + # is equivalent to + + midi_output.write_sys_ex(pygame.midi.time(), + [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7]) + + .. ## Output.write_sys_ex ## + + .. ## pygame.midi.Output ## + +.. function:: get_count + + | :sl:`gets the number of devices.` + | :sg:`get_count() -> num_devices` + + Device ids range from 0 to ``get_count() - 1`` + + .. ## pygame.midi.get_count ## + +.. function:: get_default_input_id + + | :sl:`gets default input device number` + | :sg:`get_default_input_id() -> default_id` + + The following describes the usage details for this function and the + :func:`get_default_output_id` function. + + Return the default device ID or ``-1`` if there are no devices. The result + can be passed to the :class:`Input`/:class:`Output` class. + + On a PC the user can specify a default device by setting an environment + variable. To use device #1, for example: + :: + + set PM_RECOMMENDED_INPUT_DEVICE=1 + or + set PM_RECOMMENDED_OUTPUT_DEVICE=1 + + The user should first determine the available device ID by using the + supplied application "testin" or "testout". + + In general, the registry is a better place for this kind of info. With + USB devices that can come and go, using integers is not very reliable + for device identification. Under Windows, if ``PM_RECOMMENDED_INPUT_DEVICE`` + (or ``PM_RECOMMENDED_OUTPUT_DEVICE``) is NOT found in the environment, + then the default device is obtained by looking for a string in the registry + under: + :: + + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device + or + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device + + + The number of the first device with a substring that matches the + string exactly is returned. For example, if the string in the registry is + "USB" and device 1 is named "In USB MidiSport 1x1", then that will be + the default input because it contains the string "USB". + + In addition to the name, :func:`get_device_info()` returns "interf", which is + the interface name. The "interface" is the underlying software system or + API used by PortMidi to access devices. Supported interfaces: + :: + + MMSystem # the only Win32 interface currently supported + ALSA # the only Linux interface currently supported + CoreMIDI # the only Mac OS X interface currently supported + # DirectX - not implemented + # OSS - not implemented + + To specify both the interface and the device name in the registry, separate + the two with a comma and a space. The string before the comma must be a + substring of the "interf" string and the string after the space must be a + substring of the "name" name string in order to match the device. e.g.: + :: + + MMSystem, In USB MidiSport 1x1 + + .. note:: + In the current release, the default is simply the first device (the + input or output device with the lowest PmDeviceID). + + .. ## pygame.midi.get_default_input_id ## + +.. function:: get_default_output_id + + | :sl:`gets default output device number` + | :sg:`get_default_output_id() -> default_id` + + See :func:`get_default_input_id` for usage details. + + .. ## pygame.midi.get_default_output_id ## + +.. function:: get_device_info + + | :sl:`returns information about a midi device` + | :sg:`get_device_info(an_id) -> (interf, name, input, output, opened)` + | :sg:`get_device_info(an_id) -> None` + + Gets the device info for a given id. + + :param int an_id: id of the midi device being queried + + :returns: if the id is out of range ``None`` is returned, otherwise + a tuple of (interf, name, input, output, opened) is returned. + + - interf: string describing the device interface (e.g. 'ALSA') + - name: string name of the device (e.g. 'Midi Through Port-0') + - input: 1 if the device is an input device, otherwise 0 + - output: 1 if the device is an output device, otherwise 0 + - opened: 1 if the device is opened, otherwise 0 + :rtype: tuple or None + + .. ## pygame.midi.get_device_info ## + +.. function:: midis2events + + | :sl:`converts midi events to pygame events` + | :sg:`midis2events(midi_events, device_id) -> [Event, ...]` + + Takes a sequence of midi events and returns list of pygame events. + + The ``midi_events`` data is expected to be a sequence of + ``((status, data1, data2, data3), timestamp)`` midi events (all values + required). + + :returns: a list of pygame events of event type ``MIDIIN`` + :rtype: list + + .. ## pygame.midi.midis2events ## + +.. function:: time + + | :sl:`returns the current time in ms of the PortMidi timer` + | :sg:`time() -> time` + + The time is reset to 0 when the :mod:`pygame.midi` module is initialized. + + .. ## pygame.midi.time ## + + +.. function:: frequency_to_midi + + | :sl:`Converts a frequency into a MIDI note. Rounds to the closest midi note.` + | :sg:`frequency_to_midi(midi_note) -> midi_note` + + example: + :: + + frequency_to_midi(27.5) == 21 + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.frequency_to_midi ## + + +.. function:: midi_to_frequency + + | :sl:`Converts a midi note to a frequency.` + | :sg:`midi_to_frequency(midi_note) -> frequency` + + example: + :: + + midi_to_frequency(21) == 27.5 + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.midi_to_frequency ## + + +.. function:: midi_to_ansi_note + + | :sl:`Returns the Ansi Note name for a midi number.` + | :sg:`midi_to_ansi_note(midi_note) -> ansi_note` + + example: + :: + + midi_to_ansi_note(21) == 'A0' + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.midi_to_ansi_note ## + +.. exception:: MidiException + + | :sl:`exception that pygame.midi functions and classes can raise` + | :sg:`MidiException(errno) -> None` + + .. ## pygame.midi.MidiException ## + + +.. ## pygame.midi ## diff --git a/docs/ref/mixer.rst b/docs/ref/mixer.rst new file mode 100644 index 0000000..07bc793 --- /dev/null +++ b/docs/ref/mixer.rst @@ -0,0 +1,605 @@ +.. include:: common.txt + +:mod:`pygame.mixer` +=================== + +.. module:: pygame.mixer + :synopsis: pygame module for loading and playing sounds + +| :sl:`pygame module for loading and playing sounds` + +This module contains classes for loading Sound objects and controlling +playback. The mixer module is optional and depends on SDL_mixer. Your program +should test that :mod:`pygame.mixer` is available and initialized before using +it. + +The mixer module has a limited number of channels for playback of sounds. +Usually programs tell pygame to start playing audio and it selects an available +channel automatically. The default is 8 simultaneous channels, but complex +programs can get more precise control over the number of channels and their +use. + +All sound playback is mixed in background threads. When you begin to play a +Sound object, it will return immediately while the sound continues to play. A +single Sound object can also be actively played back multiple times. + +The mixer also has a special streaming channel. This is for music playback and +is accessed through the :mod:`pygame.mixer.music` module. Consider using this +module for playing long running music. Unlike mixer module, the music module +streams the music from the files without loading music at once into memory. + +The mixer module must be initialized like other pygame modules, but it has some +extra conditions. The ``pygame.mixer.init()`` function takes several optional +arguments to control the playback rate and sample size. Pygame will default to +reasonable values, but pygame cannot perform Sound resampling, so the mixer +should be initialized to match the values of your audio resources. + +``NOTE``: For less laggy sound use a smaller buffer size. The default +is set to reduce the chance of scratchy sounds on some computers. You can +change the default buffer by calling :func:`pygame.mixer.pre_init` before +:func:`pygame.mixer.init` or :func:`pygame.init` is called. For example: +``pygame.mixer.pre_init(44100,-16,2, 1024)`` + + +.. function:: init + + | :sl:`initialize the mixer module` + | :sg:`init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None` + + Initialize the mixer module for Sound loading and playback. The default + arguments can be overridden to provide specific audio mixing. Keyword + arguments are accepted. For backwards compatibility, argument values of + 0 are replaced with the startup defaults, except for ``allowedchanges``, + where -1 is used. (startup defaults may be changed by a :func:`pre_init` call). + + The size argument represents how many bits are used for each audio sample. + If the value is negative then signed sample values will be used. Positive + values mean unsigned audio samples will be used. An invalid value raises an + exception. + + The channels argument is used to specify whether to use mono or stereo. 1 + for mono and 2 for stereo. + + The buffer argument controls the number of internal samples used in the + sound mixer. The default value should work for most cases. It can be lowered + to reduce latency, but sound dropout may occur. It can be raised to larger + values to ensure playback never skips, but it will impose latency on sound + playback. The buffer size must be a power of two (if not it is rounded up to + the next nearest power of 2). + + Some platforms require the :mod:`pygame.mixer` module to be initialized + after the display modules have initialized. The top level ``pygame.init()`` + takes care of this automatically, but cannot pass any arguments to the mixer + init. To solve this, mixer has a function ``pygame.mixer.pre_init()`` to set + the proper defaults before the toplevel init is used. + + When using allowedchanges=0 it will convert the samples at runtime to match + what the hardware supports. For example a sound card may not + support 16bit sound samples, so instead it will use 8bit samples internally. + If AUDIO_ALLOW_FORMAT_CHANGE is supplied, then the requested format will + change to the closest that SDL2 supports. + + Apart from 0, allowedchanged accepts the following constants ORed together: + + - AUDIO_ALLOW_FREQUENCY_CHANGE + - AUDIO_ALLOW_FORMAT_CHANGE + - AUDIO_ALLOW_CHANNELS_CHANGE + - AUDIO_ALLOW_ANY_CHANGE + + It is safe to call this more than once, but after the mixer is initialized + you cannot change the playback arguments without first calling + ``pygame.mixer.quit()``. + + .. versionchanged:: 1.8 The default ``buffersize`` changed from 1024 to 3072. + .. versionchanged:: 1.9.1 The default ``buffersize`` changed from 3072 to 4096. + .. versionchanged:: 2.0.0 The default ``buffersize`` changed from 4096 to 512. + .. versionchanged:: 2.0.0 The default ``frequency`` changed from 22050 to 44100. + .. versionchanged:: 2.0.0 ``size`` can be 32 (32-bit floats). + .. versionchanged:: 2.0.0 ``channels`` can also be 4 or 6. + .. versionadded:: 2.0.0 ``allowedchanges``, ``devicename`` arguments added + + .. ## pygame.mixer.init ## + +.. function:: pre_init + + | :sl:`preset the mixer init arguments` + | :sg:`pre_init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None` + + Call pre_init to change the defaults used when the real + ``pygame.mixer.init()`` is called. Keyword arguments are accepted. The best + way to set custom mixer playback values is to call + ``pygame.mixer.pre_init()`` before calling the top level ``pygame.init()``. + For backwards compatibility, argument values of 0 are replaced with the + startup defaults, except for ``allowedchanges``, where -1 is used. + + .. versionchanged:: 1.8 The default ``buffersize`` changed from 1024 to 3072. + .. versionchanged:: 1.9.1 The default ``buffersize`` changed from 3072 to 4096. + .. versionchanged:: 2.0.0 The default ``buffersize`` changed from 4096 to 512. + .. versionchanged:: 2.0.0 The default ``frequency`` changed from 22050 to 44100. + .. versionadded:: 2.0.0 ``allowedchanges``, ``devicename`` arguments added + + .. ## pygame.mixer.pre_init ## + +.. function:: quit + + | :sl:`uninitialize the mixer` + | :sg:`quit() -> None` + + This will uninitialize :mod:`pygame.mixer`. All playback will stop and any + loaded Sound objects may not be compatible with the mixer if it is + reinitialized later. + + .. ## pygame.mixer.quit ## + +.. function:: get_init + + | :sl:`test if the mixer is initialized` + | :sg:`get_init() -> (frequency, format, channels)` + + If the mixer is initialized, this returns the playback arguments it is + using. If the mixer has not been initialized this returns ``None``. + + .. ## pygame.mixer.get_init ## + +.. function:: stop + + | :sl:`stop playback of all sound channels` + | :sg:`stop() -> None` + + This will stop all playback of all active mixer channels. + + .. ## pygame.mixer.stop ## + +.. function:: pause + + | :sl:`temporarily stop playback of all sound channels` + | :sg:`pause() -> None` + + This will temporarily stop all playback on the active mixer channels. The + playback can later be resumed with ``pygame.mixer.unpause()`` + + .. ## pygame.mixer.pause ## + +.. function:: unpause + + | :sl:`resume paused playback of sound channels` + | :sg:`unpause() -> None` + + This will resume all active sound channels after they have been paused. + + .. ## pygame.mixer.unpause ## + +.. function:: fadeout + + | :sl:`fade out the volume on all sounds before stopping` + | :sg:`fadeout(time) -> None` + + This will fade out the volume on all active channels over the time argument + in milliseconds. After the sound is muted the playback will stop. + + .. ## pygame.mixer.fadeout ## + +.. function:: set_num_channels + + | :sl:`set the total number of playback channels` + | :sg:`set_num_channels(count) -> None` + + Sets the number of available channels for the mixer. The default value is 8. + The value can be increased or decreased. If the value is decreased, sounds + playing on the truncated channels are stopped. + + .. ## pygame.mixer.set_num_channels ## + +.. function:: get_num_channels + + | :sl:`get the total number of playback channels` + | :sg:`get_num_channels() -> count` + + Returns the number of currently active playback channels. + + .. ## pygame.mixer.get_num_channels ## + +.. function:: set_reserved + + | :sl:`reserve channels from being automatically used` + | :sg:`set_reserved(count) -> count` + + The mixer can reserve any number of channels that will not be automatically + selected for playback by Sounds. This means that whenever you play a Sound + without specifying a channel, a reserved channel will never be used. If sounds + are currently playing on the reserved channels they will not be stopped. + + This allows the application to reserve a specific number of channels for + important sounds that must not be dropped or have a guaranteed channel to + play on. + + Will return number of channels actually reserved, this may be less than requested + depending on the number of channels previously allocated. + + .. ## pygame.mixer.set_reserved ## + +.. function:: find_channel + + | :sl:`find an unused channel` + | :sg:`find_channel(force=False) -> Channel` + + This will find and return an inactive Channel object. If there are no + inactive Channels this function will return ``None``. If there are no + inactive channels and the force argument is ``True``, this will find the + Channel with the longest running Sound and return it. + + .. ## pygame.mixer.find_channel ## + +.. function:: get_busy + + | :sl:`test if any sound is being mixed` + | :sg:`get_busy() -> bool` + + Returns ``True`` if the mixer is busy mixing any channels. If the mixer is + idle then this return ``False``. + + .. ## pygame.mixer.get_busy ## + +.. function:: get_sdl_mixer_version + + | :sl:`get the mixer's SDL version` + | :sg:`get_sdl_mixer_version() -> (major, minor, patch)` + | :sg:`get_sdl_mixer_version(linked=True) -> (major, minor, patch)` + + :param bool linked: if ``True`` (default) the linked version number is + returned, otherwise the compiled version number is returned + + :returns: the mixer's SDL library version number (linked or compiled + depending on the ``linked`` parameter) as a tuple of 3 integers + ``(major, minor, patch)`` + :rtype: tuple + + .. note:: + The linked and compile version numbers should be the same. + + .. versionadded:: 2.0.0 + + .. ## pygame.mixer.get_sdl_mixer_version ## + +.. class:: Sound + + | :sl:`Create a new Sound object from a file or buffer object` + | :sg:`Sound(filename) -> Sound` + | :sg:`Sound(file=filename) -> Sound` + | :sg:`Sound(file=pathlib_path) -> Sound` + | :sg:`Sound(buffer) -> Sound` + | :sg:`Sound(buffer=buffer) -> Sound` + | :sg:`Sound(object) -> Sound` + | :sg:`Sound(file=object) -> Sound` + | :sg:`Sound(array=object) -> Sound` + + Load a new sound buffer from a filename, a python file object or a readable + buffer object. Limited resampling will be performed to help the sample match + the initialize arguments for the mixer. A Unicode string can only be a file + pathname. A bytes object can be either a pathname or a buffer object. + Use the 'file' or 'buffer' keywords to avoid ambiguity; otherwise Sound may + guess wrong. If the array keyword is used, the object is expected to export + a new buffer interface (The object is checked for a buffer interface first.) + + The Sound object represents actual sound sample data. Methods that change + the state of the Sound object will the all instances of the Sound playback. + A Sound object also exports a new buffer interface. + + The Sound can be loaded from an ``OGG`` audio file or from an uncompressed + ``WAV``. + + Note: The buffer will be copied internally, no data will be shared between + it and the Sound object. + + For now buffer and array support is consistent with ``sndarray.make_sound`` + for Numeric arrays, in that sample sign and byte order are ignored. This + will change, either by correctly handling sign and byte order, or by raising + an exception when different. Also, source samples are truncated to fit the + audio sample size. This will not change. + + .. versionadded:: 1.8 ``pygame.mixer.Sound(buffer)`` + .. versionadded:: 1.9.2 + :class:`pygame.mixer.Sound` keyword arguments and array interface support + .. versionadded:: 2.0.1 pathlib.Path support on Python 3. + + .. method:: play + + | :sl:`begin sound playback` + | :sg:`play(loops=0, maxtime=0, fade_ms=0) -> Channel` + + Begin playback of the Sound (i.e., on the computer's speakers) on an + available Channel. This will forcibly select a Channel, so playback may + cut off a currently playing sound if necessary. + + The loops argument controls how many times the sample will be repeated + after being played the first time. A value of 5 means that the sound will + be played once, then repeated five times, and so is played a total of six + times. The default value (zero) means the Sound is not repeated, and so + is only played once. If loops is set to -1 the Sound will loop + indefinitely (though you can still call ``stop()`` to stop it). + + The maxtime argument can be used to stop playback after a given number of + milliseconds. + + The fade_ms argument will make the sound start playing at 0 volume and + fade up to full volume over the time given. The sample may end before the + fade-in is complete. + + This returns the Channel object for the channel that was selected. + + .. ## Sound.play ## + + .. method:: stop + + | :sl:`stop sound playback` + | :sg:`stop() -> None` + + This will stop the playback of this Sound on any active Channels. + + .. ## Sound.stop ## + + .. method:: fadeout + + | :sl:`stop sound playback after fading out` + | :sg:`fadeout(time) -> None` + + This will stop playback of the sound after fading it out over the time + argument in milliseconds. The Sound will fade and stop on all actively + playing channels. + + .. ## Sound.fadeout ## + + .. method:: set_volume + + | :sl:`set the playback volume for this Sound` + | :sg:`set_volume(value) -> None` + + This will set the playback volume (loudness) for this Sound. This will + immediately affect the Sound if it is playing. It will also affect any + future playback of this Sound. + + :param float value: volume in the range of 0.0 to 1.0 (inclusive) + + | If value < 0.0, the volume will not be changed + | If value > 1.0, the volume will be set to 1.0 + + .. ## Sound.set_volume ## + + .. method:: get_volume + + | :sl:`get the playback volume` + | :sg:`get_volume() -> value` + + Return a value from 0.0 to 1.0 representing the volume for this Sound. + + .. ## Sound.get_volume ## + + .. method:: get_num_channels + + | :sl:`count how many times this Sound is playing` + | :sg:`get_num_channels() -> count` + + Return the number of active channels this sound is playing on. + + .. ## Sound.get_num_channels ## + + .. method:: get_length + + | :sl:`get the length of the Sound` + | :sg:`get_length() -> seconds` + + Return the length of this Sound in seconds. + + .. ## Sound.get_length ## + + .. method:: get_raw + + | :sl:`return a bytestring copy of the Sound samples.` + | :sg:`get_raw() -> bytes` + + Return a copy of the Sound object buffer as a bytes. + + .. versionadded:: 1.9.2 + + .. ## Sound.get_raw ## + + .. ## pygame.mixer.Sound ## + +.. class:: Channel + + | :sl:`Create a Channel object for controlling playback` + | :sg:`Channel(id) -> Channel` + + Return a Channel object for one of the current channels. The id must be a + value from 0 to the value of ``pygame.mixer.get_num_channels()``. + + The Channel object can be used to get fine control over the playback of + Sounds. A channel can only playback a single Sound at time. Using channels + is entirely optional since pygame can manage them by default. + + .. method:: play + + | :sl:`play a Sound on a specific Channel` + | :sg:`play(Sound, loops=0, maxtime=0, fade_ms=0) -> None` + + This will begin playback of a Sound on a specific Channel. If the Channel + is currently playing any other Sound it will be stopped. + + The loops argument has the same meaning as in ``Sound.play()``: it is the + number of times to repeat the sound after the first time. If it is 3, the + sound will be played 4 times (the first time, then three more). If loops + is -1 then the playback will repeat indefinitely. + + As in ``Sound.play()``, the maxtime argument can be used to stop playback + of the Sound after a given number of milliseconds. + + As in ``Sound.play()``, the fade_ms argument can be used fade in the + sound. + + .. ## Channel.play ## + + .. method:: stop + + | :sl:`stop playback on a Channel` + | :sg:`stop() -> None` + + Stop sound playback on a channel. After playback is stopped the channel + becomes available for new Sounds to play on it. + + .. ## Channel.stop ## + + .. method:: pause + + | :sl:`temporarily stop playback of a channel` + | :sg:`pause() -> None` + + Temporarily stop the playback of sound on a channel. It can be resumed at + a later time with ``Channel.unpause()`` + + .. ## Channel.pause ## + + .. method:: unpause + + | :sl:`resume pause playback of a channel` + | :sg:`unpause() -> None` + + Resume the playback on a paused channel. + + .. ## Channel.unpause ## + + .. method:: fadeout + + | :sl:`stop playback after fading channel out` + | :sg:`fadeout(time) -> None` + + Stop playback of a channel after fading out the sound over the given time + argument in milliseconds. + + .. ## Channel.fadeout ## + + .. method:: set_volume + + | :sl:`set the volume of a playing channel` + | :sg:`set_volume(value) -> None` + | :sg:`set_volume(left, right) -> None` + + Set the volume (loudness) of a playing sound. When a channel starts to + play its volume value is reset. This only affects the current sound. The + value argument is between 0.0 and 1.0. + + If one argument is passed, it will be the volume of both speakers. If two + arguments are passed and the mixer is in stereo mode, the first argument + will be the volume of the left speaker and the second will be the volume + of the right speaker. (If the second argument is ``None``, the first + argument will be the volume of both speakers.) + + If the channel is playing a Sound on which ``set_volume()`` has also been + called, both calls are taken into account. For example: + + :: + + sound = pygame.mixer.Sound("s.wav") + channel = s.play() # Sound plays at full volume by default + sound.set_volume(0.9) # Now plays at 90% of full volume. + sound.set_volume(0.6) # Now plays at 60% (previous value replaced). + channel.set_volume(0.5) # Now plays at 30% (0.6 * 0.5). + + .. ## Channel.set_volume ## + + .. method:: get_volume + + | :sl:`get the volume of the playing channel` + | :sg:`get_volume() -> value` + + Return the volume of the channel for the current playing sound. This does + not take into account stereo separation used by + :meth:`Channel.set_volume`. The Sound object also has its own volume + which is mixed with the channel. + + .. ## Channel.get_volume ## + + .. method:: get_busy + + | :sl:`check if the channel is active` + | :sg:`get_busy() -> bool` + + Returns ``True`` if the channel is actively mixing sound. If the channel + is idle this returns ``False``. + + .. ## Channel.get_busy ## + + .. method:: get_sound + + | :sl:`get the currently playing Sound` + | :sg:`get_sound() -> Sound` + + Return the actual Sound object currently playing on this channel. If the + channel is idle ``None`` is returned. + + .. ## Channel.get_sound ## + + .. method:: queue + + | :sl:`queue a Sound object to follow the current` + | :sg:`queue(Sound) -> None` + + When a Sound is queued on a Channel, it will begin playing immediately + after the current Sound is finished. Each channel can only have a single + Sound queued at a time. The queued Sound will only play if the current + playback finished automatically. It is cleared on any other call to + ``Channel.stop()`` or ``Channel.play()``. + + If there is no sound actively playing on the Channel then the Sound will + begin playing immediately. + + .. ## Channel.queue ## + + .. method:: get_queue + + | :sl:`return any Sound that is queued` + | :sg:`get_queue() -> Sound` + + If a Sound is already queued on this channel it will be returned. Once + the queued sound begins playback it will no longer be on the queue. + + .. ## Channel.get_queue ## + + .. method:: set_endevent + + | :sl:`have the channel send an event when playback stops` + | :sg:`set_endevent() -> None` + | :sg:`set_endevent(type) -> None` + + When an endevent is set for a channel, it will send an event to the + pygame queue every time a sound finishes playing on that channel (not + just the first time). Use ``pygame.event.get()`` to retrieve the endevent + once it's sent. + + Note that if you called ``Sound.play(n)`` or ``Channel.play(sound,n)``, + the end event is sent only once: after the sound has been played "n+1" + times (see the documentation of Sound.play). + + If ``Channel.stop()`` or ``Channel.play()`` is called while the sound was + still playing, the event will be posted immediately. + + The type argument will be the event id sent to the queue. This can be any + valid event type, but a good choice would be a value between + ``pygame.locals.USEREVENT`` and ``pygame.locals.NUMEVENTS``. If no type + argument is given then the Channel will stop sending endevents. + + .. ## Channel.set_endevent ## + + .. method:: get_endevent + + | :sl:`get the event a channel sends when playback stops` + | :sg:`get_endevent() -> type` + + Returns the event type to be sent every time the Channel finishes + playback of a Sound. If there is no endevent the function returns + ``pygame.NOEVENT``. + + .. ## Channel.get_endevent ## + + .. ## pygame.mixer.Channel ## + +.. ## pygame.mixer ## diff --git a/docs/ref/mouse.rst b/docs/ref/mouse.rst new file mode 100644 index 0000000..dda6c7b --- /dev/null +++ b/docs/ref/mouse.rst @@ -0,0 +1,219 @@ +.. include:: common.txt + +:mod:`pygame.mouse` +=================== + +.. module:: pygame.mouse + :synopsis: pygame module to work with the mouse + +| :sl:`pygame module to work with the mouse` + +The mouse functions can be used to get the current state of the mouse device. +These functions can also alter the system cursor for the mouse. + +When the display mode is set, the event queue will start receiving mouse +events. The mouse buttons generate ``pygame.MOUSEBUTTONDOWN`` and +``pygame.MOUSEBUTTONUP`` events when they are pressed and released. These +events contain a button attribute representing which button was pressed. The +mouse wheel will generate ``pygame.MOUSEBUTTONDOWN`` and +``pygame.MOUSEBUTTONUP`` events when rolled. The button will be set to 4 +when the wheel is rolled up, and to button 5 when the wheel is rolled down. +Whenever the mouse is moved it generates a ``pygame.MOUSEMOTION`` event. The +mouse movement is broken into small and accurate motion events. As the mouse +is moving many motion events will be placed on the queue. Mouse motion events +that are not properly cleaned from the event queue are the primary reason the +event queue fills up. + +If the mouse cursor is hidden, and input is grabbed to the current display the +mouse will enter a virtual input mode, where the relative movements of the +mouse will never be stopped by the borders of the screen. See the functions +``pygame.mouse.set_visible()`` and ``pygame.event.set_grab()`` to get this +configured. + + +**Mouse Wheel Behavior in pygame 2** + +There is proper functionality for mouse wheel behaviour with pygame 2 supporting +``pygame.MOUSEWHEEL`` events. The new events support horizontal and vertical +scroll movements, with signed integer values representing the amount scrolled +(``x`` and ``y``), as well as ``flipped`` direction (the set positive and +negative values for each axis is flipped). Read more about SDL2 +input-related changes here ``_ + +In pygame 2, the mouse wheel functionality can be used by listening for the +``pygame.MOUSEWHEEL`` type of an event (Bear in mind they still emit +``pygame.MOUSEBUTTONDOWN`` events like in pygame 1.x, as well). +When this event is triggered, a developer can access the appropriate ``Event`` object +with ``pygame.event.get()``. The object can be used to access data about the mouse +scroll, such as ``which`` (it will tell you what exact mouse device trigger the event). + +.. code-block:: python + :caption: Code example of mouse scroll (tested on 2.0.0.dev7) + :name: test.py + + # Taken from husano896's PR thread (slightly modified) + import pygame + from pygame.locals import * + pygame.init() + screen = pygame.display.set_mode((640, 480)) + clock = pygame.time.Clock() + + def main(): + while True: + for event in pygame.event.get(): + if event.type == QUIT: + pygame.quit() + return + elif event.type == MOUSEWHEEL: + print(event) + print(event.x, event.y) + print(event.flipped) + print(event.which) + # can access properties with + # proper notation(ex: event.y) + clock.tick(60) + + # Execute game: + main() + +.. function:: get_pressed + + | :sl:`get the state of the mouse buttons` + | :sg:`get_pressed(num_buttons=3) -> (button1, button2, button3)` + | :sg:`get_pressed(num_buttons=5) -> (button1, button2, button3, button4, button5)` + + Returns a sequence of booleans representing the state of all the mouse + buttons. A true value means the mouse is currently being pressed at the time + of the call. + + Note, to get all of the mouse events it is better to use either + ``pygame.event.wait()`` or ``pygame.event.get()`` and check all of those + events to see if they are ``MOUSEBUTTONDOWN``, ``MOUSEBUTTONUP``, or + ``MOUSEMOTION``. + + Note, that on ``X11`` some X servers use middle button emulation. When you + click both buttons ``1`` and ``3`` at the same time a ``2`` button event + can be emitted. + + Note, remember to call ``pygame.event.get()`` before this function. + Otherwise it will not work as expected. + + To support five button mice, an optional parameter ``num_buttons`` has been + added in pygame 2. When this is set to ``5``, ``button4`` and ``button5`` + are added to the returned tuple. Only ``3`` and ``5`` are valid values + for this parameter. + + .. versionchanged:: 2.0.0 ``num_buttons`` argument added + + .. ## pygame.mouse.get_pressed ## + +.. function:: get_pos + + | :sl:`get the mouse cursor position` + | :sg:`get_pos() -> (x, y)` + + Returns the ``x`` and ``y`` position of the mouse cursor. The position is + relative to the top-left corner of the display. The cursor position can be + located outside of the display window, but is always constrained to the + screen. + + .. ## pygame.mouse.get_pos ## + +.. function:: get_rel + + | :sl:`get the amount of mouse movement` + | :sg:`get_rel() -> (x, y)` + + Returns the amount of movement in ``x`` and ``y`` since the previous call to + this function. The relative movement of the mouse cursor is constrained to + the edges of the screen, but see the virtual input mouse mode for a way + around this. Virtual input mode is described at the top of the page. + + .. ## pygame.mouse.get_rel ## + +.. function:: set_pos + + | :sl:`set the mouse cursor position` + | :sg:`set_pos([x, y]) -> None` + + Set the current mouse position to arguments given. If the mouse cursor is + visible it will jump to the new coordinates. Moving the mouse will generate + a new ``pygame.MOUSEMOTION`` event. + + .. ## pygame.mouse.set_pos ## + +.. function:: set_visible + + | :sl:`hide or show the mouse cursor` + | :sg:`set_visible(bool) -> bool` + + If the bool argument is true, the mouse cursor will be visible. This will + return the previous visible state of the cursor. + + .. ## pygame.mouse.set_visible ## + +.. function:: get_visible + + | :sl:`get the current visibility state of the mouse cursor` + | :sg:`get_visible() -> bool` + + Get the current visibility state of the mouse cursor. ``True`` if the mouse is + visible, ``False`` otherwise. + + .. versionadded:: 2.0.0 + + .. ## pygame.mouse.get_visible ## + +.. function:: get_focused + + | :sl:`check if the display is receiving mouse input` + | :sg:`get_focused() -> bool` + + Returns true when pygame is receiving mouse input events (or, in windowing + terminology, is "active" or has the "focus"). + + This method is most useful when working in a window. By contrast, in + full-screen mode, this method always returns true. + + Note: under ``MS`` Windows, the window that has the mouse focus also has the + keyboard focus. But under X-Windows, one window can receive mouse events and + another receive keyboard events. ``pygame.mouse.get_focused()`` indicates + whether the pygame window receives mouse events. + + .. ## pygame.mouse.get_focused ## + +.. function:: set_cursor + + | :sl:`set the mouse cursor to a new cursor` + | :sg:`set_cursor(pygame.cursors.Cursor) -> None` + | :sg:`set_cursor(size, hotspot, xormasks, andmasks) -> None` + | :sg:`set_cursor(hotspot, surface) -> None` + | :sg:`set_cursor(constant) -> None` + + Set the mouse cursor to something new. This function accepts either an explicit + ``Cursor`` object or arguments to create a ``Cursor`` object. + + See :class:`pygame.cursors.Cursor` for help creating cursors and for examples. + + .. versionchanged:: 2.0.1 + + .. ## pygame.mouse.set_cursor ## + + +.. function:: get_cursor + + | :sl:`get the current mouse cursor` + | :sg:`get_cursor() -> pygame.cursors.Cursor` + + Get the information about the mouse system cursor. The return value contains + the same data as the arguments passed into :func:`pygame.mouse.set_cursor()`. + + .. note:: Code that unpacked a get_cursor() call into + ``size, hotspot, xormasks, andmasks`` will still work, + assuming the call returns an old school type cursor. + + .. versionchanged:: 2.0.1 + + .. ## pygame.mouse.get_cursor ## + +.. ## pygame.mouse ## diff --git a/docs/ref/music.rst b/docs/ref/music.rst new file mode 100644 index 0000000..96a7b81 --- /dev/null +++ b/docs/ref/music.rst @@ -0,0 +1,274 @@ +.. include:: common.txt + +:mod:`pygame.mixer.music` +========================= + +.. module:: pygame.mixer.music + :synopsis: pygame module for controlling streamed audio + +| :sl:`pygame module for controlling streamed audio` + +The music module is closely tied to :mod:`pygame.mixer`. Use the music module +to control the playback of music in the sound mixer. + +The difference between the music playback and regular Sound playback is that +the music is streamed, and never actually loaded all at once. The mixer system +only supports a single music stream at once. + +On older pygame versions, ``MP3`` support was limited under Mac and Linux. This +changed in pygame ``v2.0.2`` which got improved MP3 support. Consider using +``OGG`` file format for music as that can give slightly better compression than +MP3 in most cases. + +.. function:: load + + | :sl:`Load a music file for playback` + | :sg:`load(filename) -> None` + | :sg:`load(fileobj, namehint="") -> None` + + This will load a music filename/file object and prepare it for playback. If + a music stream is already playing it will be stopped. This does not start + the music playing. + + If you are loading from a file object, the namehint parameter can be used to specify + the type of music data in the object. For example: :code:`load(fileobj, "ogg")`. + + .. versionchanged:: 2.0.2 Added optional ``namehint`` argument + + .. ## pygame.mixer.music.load ## + +.. function:: unload + + | :sl:`Unload the currently loaded music to free up resources` + | :sg:`unload() -> None` + + This closes resources like files for any music that may be loaded. + + .. versionadded:: 2.0.0 + + .. ## pygame.mixer.music.load ## + + +.. function:: play + + | :sl:`Start the playback of the music stream` + | :sg:`play(loops=0, start=0.0, fade_ms=0) -> None` + + This will play the loaded music stream. If the music is already playing it + will be restarted. + + ``loops`` is an optional integer argument, which is ``0`` by default, which + indicates how many times to repeat the music. The music repeats indefinitely if + this argument is set to ``-1``. + + ``start`` is an optional float argument, which is ``0.0`` by default, which + denotes the position in time from which the music starts playing. The starting + position depends on the format of the music played. ``MP3`` and ``OGG`` use + the position as time in seconds. For ``MP3`` files the start time position + selected may not be accurate as things like variable bit rate encoding and ID3 + tags can throw off the timing calculations. For ``MOD`` music it is the pattern + order number. Passing a start position will raise a NotImplementedError if + the start position cannot be set. + + ``fade_ms`` is an optional integer argument, which is ``0`` by default, + which denotes the period of time (in milliseconds) over which the music + will fade up from volume level ``0.0`` to full volume (or the volume level + previously set by :func:`set_volume`). The sample may end before the fade-in + is complete. If the music is already streaming ``fade_ms`` is ignored. + + .. versionchanged:: 2.0.0 Added optional ``fade_ms`` argument + + .. ## pygame.mixer.music.play ## + +.. function:: rewind + + | :sl:`restart music` + | :sg:`rewind() -> None` + + Resets playback of the current music to the beginning. If :func:`pause` has + previously been used to pause the music, the music will remain paused. + + .. note:: :func:`rewind` supports a limited number of file types and notably + ``WAV`` files are NOT supported. For unsupported file types use :func:`play` + which will restart the music that's already playing (note that this + will start the music playing again even if previously paused). + + .. ## pygame.mixer.music.rewind ## + +.. function:: stop + + | :sl:`stop the music playback` + | :sg:`stop() -> None` + + Stops the music playback if it is currently playing. + endevent will be triggered, if set. + It won't unload the music. + + .. ## pygame.mixer.music.stop ## + +.. function:: pause + + | :sl:`temporarily stop music playback` + | :sg:`pause() -> None` + + Temporarily stop playback of the music stream. It can be resumed with the + :func:`unpause` function. + + .. ## pygame.mixer.music.pause ## + +.. function:: unpause + + | :sl:`resume paused music` + | :sg:`unpause() -> None` + + This will resume the playback of a music stream after it has been paused. + + .. ## pygame.mixer.music.unpause ## + +.. function:: fadeout + + | :sl:`stop music playback after fading out` + | :sg:`fadeout(time) -> None` + + Fade out and stop the currently playing music. + + The ``time`` argument denotes the integer milliseconds for which the + fading effect is generated. + + Note, that this function blocks until the music has faded out. Calls + to :func:`fadeout` and :func:`set_volume` will have no effect during + this time. If an event was set using :func:`set_endevent` it will be + called after the music has faded. + + .. ## pygame.mixer.music.fadeout ## + +.. function:: set_volume + + | :sl:`set the music volume` + | :sg:`set_volume(volume) -> None` + + Set the volume of the music playback. + + The ``volume`` argument is a float between ``0.0`` and ``1.0`` that sets + the volume level. When new music is loaded the volume is reset to full + volume. If ``volume`` is a negative value it will be ignored and the + volume will remain set at the current level. If the ``volume`` argument + is greater than ``1.0``, the volume will be set to ``1.0``. + + .. ## pygame.mixer.music.set_volume ## + +.. function:: get_volume + + | :sl:`get the music volume` + | :sg:`get_volume() -> value` + + Returns the current volume for the mixer. The value will be between ``0.0`` + and ``1.0``. + + .. ## pygame.mixer.music.get_volume ## + +.. function:: get_busy + + | :sl:`check if the music stream is playing` + | :sg:`get_busy() -> bool` + + Returns True when the music stream is actively playing. When the music is + idle this returns False. In pygame 2.0.1 and above this function returns + False when the music is paused. In pygame 1 it returns True when the music + is paused. + + .. versionchanged:: 2.0.1 Returns False when music paused. + + .. ## pygame.mixer.music.get_busy ## + +.. function:: set_pos + + | :sl:`set position to play from` + | :sg:`set_pos(pos) -> None` + + This sets the position in the music file where playback will start. + The meaning of "pos", a float (or a number that can be converted to a float), + depends on the music format. + + For ``MOD`` files, pos is the integer pattern number in the module. + For ``OGG`` it is the absolute position, in seconds, from + the beginning of the sound. For ``MP3`` files, it is the relative position, + in seconds, from the current position. For absolute positioning in an ``MP3`` + file, first call :func:`rewind`. + + Other file formats are unsupported. Newer versions of SDL_mixer have + better positioning support than earlier ones. An SDLError is raised if a + particular format does not support positioning. + + Function :func:`set_pos` calls underlining SDL_mixer function + ``Mix_SetMusicPosition``. + + .. versionadded:: 1.9.2 + + .. ## pygame.mixer.music.set_pos ## + +.. function:: get_pos + + | :sl:`get the music play time` + | :sg:`get_pos() -> time` + + This gets the number of milliseconds that the music has been playing for. + The returned time only represents how long the music has been playing; it + does not take into account any starting position offsets. + + .. ## pygame.mixer.music.get_pos ## + +.. function:: queue + + | :sl:`queue a sound file to follow the current` + | :sg:`queue(filename) -> None` + | :sg:`queue(fileobj, namehint="", loops=0) -> None` + + This will load a sound file and queue it. A queued sound file will begin as + soon as the current sound naturally ends. Only one sound can be queued at a + time. Queuing a new sound while another sound is queued will result in the + new sound becoming the queued sound. Also, if the current sound is ever + stopped or changed, the queued sound will be lost. + + If you are loading from a file object, the namehint parameter can be used to specify + the type of music data in the object. For example: :code:`queue(fileobj, "ogg")`. + + The following example will play music by Bach six times, then play music by + Mozart once: + + :: + + pygame.mixer.music.load('bach.ogg') + pygame.mixer.music.play(5) # Plays six times, not five! + pygame.mixer.music.queue('mozart.ogg') + + .. versionchanged:: 2.0.2 Added optional ``namehint`` argument + + .. ## pygame.mixer.music.queue ## + +.. function:: set_endevent + + | :sl:`have the music send an event when playback stops` + | :sg:`set_endevent() -> None` + | :sg:`set_endevent(type) -> None` + + This causes pygame to signal (by means of the event queue) when the music is + done playing. The argument determines the type of event that will be queued. + + The event will be queued every time the music finishes, not just the first + time. To stop the event from being queued, call this method with no + argument. + + .. ## pygame.mixer.music.set_endevent ## + +.. function:: get_endevent + + | :sl:`get the event a channel sends when playback stops` + | :sg:`get_endevent() -> type` + + Returns the event type to be sent every time the music finishes playback. If + there is no endevent the function returns ``pygame.NOEVENT``. + + .. ## pygame.mixer.music.get_endevent ## + +.. ## pygame.mixer.music ## diff --git a/docs/ref/overlay.rst b/docs/ref/overlay.rst new file mode 100644 index 0000000..04ff9ae --- /dev/null +++ b/docs/ref/overlay.rst @@ -0,0 +1,79 @@ +.. include:: common.txt + +:mod:`pygame.Overlay` +===================== + +.. currentmodule:: pygame + +.. warning:: + This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. + This module will not be supported in the future. + +.. class:: Overlay + + | :sl:`pygame object for video overlay graphics` + | :sg:`Overlay(format, (width, height)) -> Overlay` + + The Overlay objects provide support for accessing hardware video overlays. + Video overlays do not use standard ``RGB`` pixel formats, and can use + multiple resolutions of data to create a single image. + + The Overlay objects represent lower level access to the display hardware. To + use the object you must understand the technical details of video overlays. + + The Overlay format determines the type of pixel data used. Not all hardware + will support all types of overlay formats. Here is a list of available + format types: + + :: + + YV12_OVERLAY, IYUV_OVERLAY, YUY2_OVERLAY, UYVY_OVERLAY, YVYU_OVERLAY + + The width and height arguments control the size for the overlay image data. + The overlay image can be displayed at any size, not just the resolution of + the overlay. + + The overlay objects are always visible, and always show above the regular + display contents. + + .. method:: display + + | :sl:`set the overlay pixel data` + | :sg:`display((y, u, v)) -> None` + | :sg:`display() -> None` + + Display the YUV data in SDL's overlay planes. The y, u, and v arguments + are strings of binary data. The data must be in the correct format used + to create the Overlay. + + If no argument is passed in, the Overlay will simply be redrawn with the + current data. This can be useful when the Overlay is not really hardware + accelerated. + + The strings are not validated, and improperly sized strings could crash + the program. + + .. ## Overlay.display ## + + .. method:: set_location + + | :sl:`control where the overlay is displayed` + | :sg:`set_location(rect) -> None` + + Set the location for the overlay. The overlay will always be shown + relative to the main display Surface. This does not actually redraw the + overlay, it will be updated on the next call to ``Overlay.display()``. + + .. ## Overlay.set_location ## + + .. method:: get_hardware + + | :sl:`test if the Overlay is hardware accelerated` + | :sg:`get_hardware(rect) -> int` + + Returns a True value when the Overlay is hardware accelerated. If the + platform does not support acceleration, software rendering is used. + + .. ## Overlay.get_hardware ## + + .. ## pygame.Overlay ## diff --git a/docs/ref/pixelarray.rst b/docs/ref/pixelarray.rst new file mode 100644 index 0000000..9bdc38c --- /dev/null +++ b/docs/ref/pixelarray.rst @@ -0,0 +1,295 @@ +.. include:: common.txt + +:class:`pygame.PixelArray` +========================== + +.. currentmodule:: pygame + +.. class:: PixelArray + + | :sl:`pygame object for direct pixel access of surfaces` + | :sg:`PixelArray(Surface) -> PixelArray` + + The PixelArray wraps a Surface and provides direct access to the + surface's pixels. A pixel array can be one or two dimensional. + A two dimensional array, like its surface, is indexed [column, row]. + Pixel arrays support slicing, both for returning a subarray or + for assignment. A pixel array sliced on a single column or row + returns a one dimensional pixel array. Arithmetic and other operations + are not supported. A pixel array can be safely assigned to itself. + Finally, pixel arrays export an array struct interface, allowing + them to interact with :mod:`pygame.pixelcopy` methods and NumPy + arrays. + + A PixelArray pixel item can be assigned a raw integer values, a + :class:`pygame.Color` instance, or a (r, g, b[, a]) tuple. + + :: + + pxarray[x, y] = 0xFF00FF + pxarray[x, y] = pygame.Color(255, 0, 255) + pxarray[x, y] = (255, 0, 255) + + However, only a pixel's integer value is returned. So, to compare a pixel + to a particular color the color needs to be first mapped using + the :meth:`Surface.map_rgb()` method of the Surface object for which the + PixelArray was created. + + :: + + pxarray = pygame.PixelArray(surface) + # Check, if the first pixel at the topleft corner is blue + if pxarray[0, 0] == surface.map_rgb((0, 0, 255)): + ... + + When assigning to a range of of pixels, a non tuple sequence of colors or + a PixelArray can be used as the value. For a sequence, the length must + match the PixelArray width. + + :: + + pxarray[a:b] = 0xFF00FF # set all pixels to 0xFF00FF + pxarray[a:b] = (0xFF00FF, 0xAACCEE, ... ) # first pixel = 0xFF00FF, + # second pixel = 0xAACCEE, ... + pxarray[a:b] = [(255, 0, 255), (170, 204, 238), ...] # same as above + pxarray[a:b] = [(255, 0, 255), 0xAACCEE, ...] # same as above + pxarray[a:b] = otherarray[x:y] # slice sizes must match + + For PixelArray assignment, if the right hand side array has a row length + of 1, then the column is broadcast over the target array's rows. An + array of height 1 is broadcast over the target's columns, and is equivalent + to assigning a 1D PixelArray. + + Subscript slices can also be used to assign to a rectangular subview of + the target PixelArray. + + :: + + # Create some new PixelArray objects providing a different view + # of the original array/surface. + newarray = pxarray[2:4, 3:5] + otherarray = pxarray[::2, ::2] + + Subscript slices can also be used to do fast rectangular pixel manipulations + instead of iterating over the x or y axis. The + + :: + + pxarray[::2, :] = (0, 0, 0) # Make even columns black. + pxarray[::2] = (0, 0, 0) # Same as [::2, :] + + During its lifetime, the PixelArray locks the surface, thus you explicitly + have to close() it once its not used any more and the surface should perform + operations in the same scope. It is best to use it as a context manager + using the with PixelArray(surf) as pixel_array: style. So it works on pypy too. + + A simple ``:`` slice index for the column can be omitted. + + :: + + pxarray[::2, ...] = (0, 0, 0) # Same as pxarray[::2, :] + pxarray[...] = (255, 0, 0) # Same as pxarray[:] + + A note about PixelArray to PixelArray assignment, for arrays with an + item size of 3 (created from 24 bit surfaces) pixel values are translated + from the source to the destinations format. The red, green, and blue + color elements of each pixel are shifted to match the format of the + target surface. For all other pixel sizes no such remapping occurs. + This should change in later pygame releases, where format conversions + are performed for all pixel sizes. To avoid code breakage when full mapped + copying is implemented it is suggested PixelArray to PixelArray copies be + only between surfaces of identical format. + + .. versionadded:: 1.9.4 + + - close() method was added. For explicitly cleaning up. + - being able to use PixelArray as a context manager for cleanup. + - both of these are useful for when working without reference counting (pypy). + + .. versionadded:: 1.9.2 + + - array struct interface + - transpose method + - broadcasting for a length 1 dimension + + .. versionchanged:: 1.9.2 + + - A 2D PixelArray can have a length 1 dimension. + Only an integer index on a 2D PixelArray returns a 1D array. + - For assignment, a tuple can only be a color. Any other sequence type + is a sequence of colors. + + + .. versionadded: 1.8.0 + Subscript support + + .. versionadded: 1.8.1 + Methods :meth:`make_surface`, :meth:`replace`, :meth:`extract`, and + :meth:`compare` + + .. versionadded: 1.9.2 + Properties :attr:`itemsize`, :attr:`ndim`, :attr:`shape`, + and :attr:`strides` + + .. versionadded: 1.9.2 + Array struct interface + + .. versionadded: 1.9.4 + Methods :meth:`close` + + .. attribute:: surface + + | :sl:`Gets the Surface the PixelArray uses.` + | :sg:`surface -> Surface` + + The Surface the PixelArray was created for. + + .. ## PixelArray.surface ## + + .. attribute:: itemsize + + | :sl:`Returns the byte size of a pixel array item` + | :sg:`itemsize -> int` + + This is the same as :meth:`Surface.get_bytesize` for the + pixel array's surface. + + .. versionadded:: 1.9.2 + + .. attribute:: ndim + + | :sl:`Returns the number of dimensions.` + | :sg:`ndim -> int` + + A pixel array can be 1 or 2 dimensional. + + .. versionadded:: 1.9.2 + + .. attribute:: shape + + | :sl:`Returns the array size.` + | :sg:`shape -> tuple of int's` + + A tuple or length :attr:`ndim` giving the length of each + dimension. Analogous to :meth:`Surface.get_size`. + + .. versionadded:: 1.9.2 + + .. attribute:: strides + + | :sl:`Returns byte offsets for each array dimension.` + | :sg:`strides -> tuple of int's` + + A tuple or length :attr:`ndim` byte counts. When a stride is + multiplied by the corresponding index it gives the offset + of that index from the start of the array. A stride is negative + for an array that has is inverted (has a negative step). + + .. versionadded:: 1.9.2 + + .. method:: make_surface + + | :sl:`Creates a new Surface from the current PixelArray.` + | :sg:`make_surface() -> Surface` + + Creates a new Surface from the current PixelArray. Depending on the + current PixelArray the size, pixel order etc. will be different from the + original Surface. + + :: + + # Create a new surface flipped around the vertical axis. + sf = pxarray[:,::-1].make_surface () + + .. versionadded:: 1.8.1 + + .. ## PixelArray.make_surface ## + + .. method:: replace + + | :sl:`Replaces the passed color in the PixelArray with another one.` + | :sg:`replace(color, repcolor, distance=0, weights=(0.299, 0.587, 0.114)) -> None` + + Replaces the pixels with the passed color in the PixelArray by changing + them them to the passed replacement color. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as threshold for the color detection. This causes the + replacement to take pixels with a similar, but not exactly identical + color, into account as well. + + This is an in place operation that directly affects the pixels of the + PixelArray. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.replace ## + + .. method:: extract + + | :sl:`Extracts the passed color from the PixelArray.` + | :sg:`extract(color, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray` + + Extracts the passed color by changing all matching pixels to white, while + non-matching pixels are changed to black. This returns a new PixelArray + with the black/white color mask. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as threshold for the color detection. This causes the + extraction to take pixels with a similar, but not exactly identical + color, into account as well. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.extract ## + + .. method:: compare + + | :sl:`Compares the PixelArray with another one.` + | :sg:`compare(array, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray` + + Compares the contents of the PixelArray with those from the passed in + PixelArray. It returns a new PixelArray with a black/white color mask + that indicates the differences (black) of both arrays. Both PixelArray + objects must have identical bit depths and dimensions. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as a threshold for the color detection. This causes the + comparison to mark pixels with a similar, but not exactly identical + color, as white. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.compare ## + + .. method:: transpose + + | :sl:`Exchanges the x and y axis.` + | :sg:`transpose() -> PixelArray` + + This method returns a new view of the pixel array with the rows and + columns swapped. So for a (w, h) sized array a (h, w) slice is returned. + If an array is one dimensional, then a length 1 x dimension is added, + resulting in a 2D pixel array. + + .. versionadded:: 1.9.2 + + .. ## PixelArray.transpose ## + + .. method:: close + + | :sl:`Closes the PixelArray, and releases Surface lock.` + | :sg:`close() -> PixelArray` + + This method is for explicitly closing the PixelArray, and releasing + a lock on the Surface. + + .. versionadded:: 1.9.4 + + .. ## PixelArray.close ## + + + .. ## pygame.PixelArray ## diff --git a/docs/ref/pixelcopy.rst b/docs/ref/pixelcopy.rst new file mode 100644 index 0000000..dd8ecf7 --- /dev/null +++ b/docs/ref/pixelcopy.rst @@ -0,0 +1,104 @@ +.. include:: common.txt + +:mod:`pygame.pixelcopy` +======================= + +.. module:: pygame.pixelcopy + :synopsis: pygame module for general pixel array copying + +| :sl:`pygame module for general pixel array copying` + +The ``pygame.pixelcopy`` module contains functions for copying between +surfaces and objects exporting an array structure interface. It is a backend +for :mod:`pygame.surfarray`, adding NumPy support. But pixelcopy is more +general, and intended for direct use. + +The array struct interface exposes an array's data in a standard way. +It was introduced in NumPy. In Python 2.7 and above it is replaced by the +new buffer protocol, though the buffer protocol is still a work in progress. +The array struct interface, on the other hand, is stable and works with earlier +Python versions. So for now the array struct interface is the predominate way +pygame handles array introspection. + +For 2d arrays of integer pixel values, the values are mapped to the +pixel format of the related surface. To get the actual color of a pixel +value use :meth:`pygame.Surface.unmap_rgb`. 2d arrays can only be used +directly between surfaces having the same pixel layout. + +New in pygame 1.9.2. + +.. function:: surface_to_array + + | :sl:`copy surface pixels to an array object` + | :sg:`surface_to_array(array, surface, kind='P', opaque=255, clear=0) -> None` + + The surface_to_array function copies pixels from a Surface object + to a 2D or 3D array. Depending on argument ``kind`` and the target array + dimension, a copy may be raw pixel value, RGB, a color component slice, + or colorkey alpha transparency value. Recognized ``kind`` values are the + single character codes 'P', 'R', 'G', 'B', 'A', and 'C'. Kind codes are case + insensitive, so 'p' is equivalent to 'P'. The first two dimensions + of the target must be the surface size (w, h). + + The default 'P' kind code does a direct raw integer pixel (mapped) value + copy to a 2D array and a 'RGB' pixel component (unmapped) copy to a 3D array + having shape (w, h, 3). For an 8 bit colormap surface this means the + table index is copied to a 2D array, not the table value itself. A 2D + array's item size must be at least as large as the surface's pixel + byte size. The item size of a 3D array must be at least one byte. + + For the 'R', 'G', 'B', and 'A' copy kinds a single color component + of the unmapped surface pixels are copied to the target 2D array. + For kind 'A' and surfaces with source alpha (the surface was created with + the SRCALPHA flag), has a colorkey + (set with :meth:`Surface.set_colorkey() `), + or has a blanket alpha + (set with :meth:`Surface.set_alpha() `) + then the alpha values are those expected for a SDL surface. + If a surface has no explicit alpha value, then the target array + is filled with the value of the optional ``opaque`` surface_to_array + argument (default 255: not transparent). + + Copy kind 'C' is a special case for alpha copy of a source surface + with colorkey. Unlike the 'A' color component copy, the ``clear`` + argument value is used for colorkey matches, ``opaque`` otherwise. + By default, a match has alpha 0 (totally transparent), while everything + else is alpha 255 (totally opaque). It is a more general implementation + of :meth:`pygame.surfarray.array_colorkey`. + + Specific to surface_to_array, a ValueError is raised for target arrays + with incorrect shape or item size. A TypeError is raised for an incorrect + kind code. Surface specific problems, such as locking, raise a pygame.error. + + .. ## pygame.pixelcopy.surface_to_array ## + +.. function:: array_to_surface + + | :sl:`copy an array object to a surface` + | :sg:`array_to_surface(, ) -> None` + + See :func:`pygame.surfarray.blit_array`. + + .. ## pygame.pixelcopy.array_to_surface ## + +.. function:: map_array + + | :sl:`copy an array to another array, using surface format` + | :sg:`map_array(, , ) -> None` + + Map an array of color element values - (w, h, ..., 3) - to an array of + pixels - (w, h) according to the format of . + + .. ## pygame.pixelcopy.map_array ## + +.. function:: make_surface + + | :sl:`Copy an array to a new surface` + | :sg:`pygame.pixelcopy.make_surface(array) -> Surface` + + Create a new Surface that best resembles the data and format of the array. + The array can be 2D or 3D with any sized integer values. + + .. ## pygame.pixelcopy.make_surface ## + +.. ## pygame.pixelcopy ## diff --git a/docs/ref/pygame.rst b/docs/ref/pygame.rst new file mode 100644 index 0000000..280831a --- /dev/null +++ b/docs/ref/pygame.rst @@ -0,0 +1,505 @@ +.. include:: common.txt + +:mod:`pygame` +============= + +.. module:: pygame + :synopsis: the top level pygame package + +| :sl:`the top level pygame package` + +The pygame package represents the top-level package for others to use. Pygame +itself is broken into many submodules, but this does not affect programs that +use pygame. + +As a convenience, most of the top-level variables in pygame have been placed +inside a module named :mod:`pygame.locals`. This is meant to be used with +``from pygame.locals import *``, in addition to ``import pygame``. + +When you ``import pygame`` all available pygame submodules are automatically +imported. Be aware that some of the pygame modules are considered *optional*, +and may not be available. In that case, pygame will provide a placeholder +object instead of the module, which can be used to test for availability. + +.. function:: init + + | :sl:`initialize all imported pygame modules` + | :sg:`init() -> (numpass, numfail)` + + Initialize all imported pygame modules. No exceptions will be raised if a + module fails, but the total number if successful and failed inits will be + returned as a tuple. You can always initialize individual modules manually, + but :func:`pygame.init` is a convenient way to get everything started. The + ``init()`` functions for individual modules will raise exceptions when they + fail. + + You may want to initialize the different modules separately to speed up your + program or to not use modules your game does not require. + + It is safe to call this ``init()`` more than once as repeated calls will have + no effect. This is true even if you have ``pygame.quit()`` all the modules. + + .. ## pygame.init ## + +.. function:: quit + + | :sl:`uninitialize all pygame modules` + | :sg:`quit() -> None` + + Uninitialize all pygame modules that have previously been initialized. When + the Python interpreter shuts down, this method is called regardless, so your + program should not need it, except when it wants to terminate its pygame + resources and continue. It is safe to call this function more than once as + repeated calls have no effect. + + .. note:: + Calling :func:`pygame.quit` will not exit your program. Consider letting + your program end in the same way a normal Python program will end. + + .. ## pygame.quit ## + +.. function:: get_init + + | :sl:`returns True if pygame is currently initialized` + | :sg:`get_init() -> bool` + + Returns ``True`` if pygame is currently initialized. + + .. versionadded:: 1.9.5 + + .. ## pygame.get_init ## + +.. exception:: error + + | :sl:`standard pygame exception` + | :sg:`raise pygame.error(message)` + + This exception is raised whenever a pygame or SDL operation fails. You + can catch any anticipated problems and deal with the error. The exception is + always raised with a descriptive message about the problem. + + Derived from the ``RuntimeError`` exception, which can also be used to catch + these raised errors. + + .. ## pygame.error ## + +.. function:: get_error + + | :sl:`get the current error message` + | :sg:`get_error() -> errorstr` + + SDL maintains an internal error message. This message will usually be + given to you when :func:`pygame.error` is raised, so this function will + rarely be needed. + + .. ## pygame.get_error ## + +.. function:: set_error + + | :sl:`set the current error message` + | :sg:`set_error(error_msg) -> None` + + SDL maintains an internal error message. This message will usually be + given to you when :func:`pygame.error` is raised, so this function will + rarely be needed. + + .. ## pygame.set_error ## + +.. function:: get_sdl_version + + | :sl:`get the version number of SDL` + | :sg:`get_sdl_version(linked=True) -> major, minor, patch` + + Returns the three version numbers of the SDL library. ``linked=True`` + will cause the function to return the version of the library that pygame + is linked against while ``linked=False`` will cause the function to return + the version of the library that pygame is compiled against. + It can be used to detect which features may or may not be + available through pygame. + + .. versionadded:: 1.7.0 + + .. versionchanged:: 2.2.0 ``linked`` keyword argument added + + .. ## pygame.get_sdl_version ## + +.. function:: get_sdl_byteorder + + | :sl:`get the byte order of SDL` + | :sg:`get_sdl_byteorder() -> int` + + Returns the byte order of the SDL library. It returns ``1234`` for little + endian byte order and ``4321`` for big endian byte order. + + .. versionadded:: 1.8 + + .. ## pygame.get_sdl_byteorder ## + +.. function:: register_quit + + | :sl:`register a function to be called when pygame quits` + | :sg:`register_quit(callable) -> None` + + When :func:`pygame.quit` is called, all registered quit functions are + called. Pygame modules do this automatically when they are initializing, so + this function will rarely be needed. + + .. ## pygame.register_quit ## + +.. function:: encode_string + + | :sl:`Encode a Unicode or bytes object` + | :sg:`encode_string([obj [, encoding [, errors [, etype]]]]) -> bytes or None` + + obj: If Unicode, encode; if bytes, return unaltered; if anything else, + return ``None``; if not given, raise ``SyntaxError``. + + encoding (string): If present, encoding to use. The default is + ``'unicode_escape'``. + + errors (string): If given, how to handle unencodable characters. The default + is ``'backslashreplace'``. + + etype (exception type): If given, the exception type to raise for an + encoding error. The default is ``UnicodeEncodeError``, as returned by + ``PyUnicode_AsEncodedString()``. For the default encoding and errors values + there should be no encoding errors. + + This function is used in encoding file paths. Keyword arguments are + supported. + + .. versionadded:: 1.9.2 (primarily for use in unit tests) + + .. ## pygame.encode_string ## + +.. function:: encode_file_path + + | :sl:`Encode a Unicode or bytes object as a file system path` + | :sg:`encode_file_path([obj [, etype]]) -> bytes or None` + + obj: If Unicode, encode; if bytes, return unaltered; if anything else, + return ``None``; if not given, raise ``SyntaxError``. + + etype (exception type): If given, the exception type to raise for an + encoding error. The default is ``UnicodeEncodeError``, as returned by + ``PyUnicode_AsEncodedString()``. + + This function is used to encode file paths in pygame. Encoding is to the + codec as returned by ``sys.getfilesystemencoding()``. Keyword arguments are + supported. + + .. versionadded:: 1.9.2 (primarily for use in unit tests) + + .. ## pygame.encode_file_path ## + + +:mod:`pygame.version` +===================== + +.. module:: pygame.version + :synopsis: small module containing version information + +| :sl:`small module containing version information` + +This module is automatically imported into the pygame package and can be used to +check which version of pygame has been imported. + +.. data:: ver + + | :sl:`version number as a string` + | :sg:`ver = '1.2'` + + This is the version represented as a string. It can contain a micro release + number as well, e.g. ``'1.5.2'`` + + .. ## pygame.version.ver ## + +.. data:: vernum + + | :sl:`tupled integers of the version` + | :sg:`vernum = (1, 5, 3)` + + This version information can easily be compared with other version + numbers of the same format. An example of checking pygame version numbers + would look like this: + + :: + + if pygame.version.vernum < (1, 5): + print('Warning, older version of pygame (%s)' % pygame.version.ver) + disable_advanced_features = True + + .. versionadded:: 1.9.6 Attributes ``major``, ``minor``, and ``patch``. + + :: + + vernum.major == vernum[0] + vernum.minor == vernum[1] + vernum.patch == vernum[2] + + .. versionchanged:: 1.9.6 + ``str(pygame.version.vernum)`` returns a string like ``"2.0.0"`` instead + of ``"(2, 0, 0)"``. + + .. versionchanged:: 1.9.6 + ``repr(pygame.version.vernum)`` returns a string like + ``"PygameVersion(major=2, minor=0, patch=0)"`` instead of ``"(2, 0, 0)"``. + + .. ## pygame.version.vernum ## + +.. data:: rev + + | :sl:`repository revision of the build` + | :sg:`rev = 'a6f89747b551+'` + + The Mercurial node identifier of the repository checkout from which this + package was built. If the identifier ends with a plus sign '+' then the + package contains uncommitted changes. Please include this revision number + in bug reports, especially for non-release pygame builds. + + Important note: pygame development has moved to github, this variable is + obsolete now. As soon as development shifted to github, this variable started + returning an empty string ``""``. + It has always been returning an empty string since ``v1.9.5``. + + .. versionchanged:: 1.9.5 + Always returns an empty string ``""``. + + .. ## pygame.version.rev ## + +.. data:: SDL + + | :sl:`tupled integers of the SDL library version` + | :sg:`SDL = '(2, 0, 12)'` + + This is the SDL library version represented as an extended tuple. It also has + attributes 'major', 'minor' & 'patch' that can be accessed like this: + + :: + + >>> pygame.version.SDL.major + 2 + + printing the whole thing returns a string like this: + + :: + + >>> pygame.version.SDL + SDLVersion(major=2, minor=0, patch=12) + + .. versionadded:: 2.0.0 + + .. ## pygame.version.SDL ## + +.. ## pygame.version ## + +.. ## pygame ## + +.. _environment-variables: + +**Setting Environment Variables** + +Some aspects of pygame's behaviour can be controlled by setting environment variables, they cover a wide +range of the library's functionality. Some of the variables are from pygame itself, while others come from +the underlying C SDL library that pygame uses. + +In python, environment variables are usually set in code like this:: + + import os + os.environ['NAME_OF_ENVIRONMENT_VARIABLE'] = 'value_to_set' + +Or to preserve users ability to override the variable:: + + import os + os.environ['ENV_VAR'] = os.environ.get('ENV_VAR', 'value') + +If the variable is more useful for users of an app to set than the developer then they can set it like this: + +**Windows**:: + + set NAME_OF_ENVIRONMENT_VARIABLE=value_to_set + python my_application.py + +**Linux/Mac**:: + + ENV_VAR=value python my_application.py + +For some variables they need to be set before initialising pygame, some must be set before even importing pygame, +and others can simply be set right before the area of code they control is run. + +Below is a list of environment variables, their settable values, and a brief description of what they do. + +| + +**Pygame Environment Variables** + +These variables are defined by pygame itself. + +| + +:: + + PYGAME_DISPLAY - Experimental (subject to change) + Set index of the display to use, "0" is the default. + +This sets the display where pygame will open its window +or screen. The value set here will be used if set before +calling :func:`pygame.display.set_mode()`, and as long as no +'display' parameter is passed into :func:`pygame.display.set_mode()`. + +| + +:: + + PYGAME_FORCE_SCALE - + Set to "photo" or "default". + +This forces set_mode() to use the SCALED display mode and, +if "photo" is set, makes the scaling use the slowest, but +highest quality anisotropic scaling algorithm, if it is +available. Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + PYGAME_BLEND_ALPHA_SDL2 - New in pygame 2.0.0 + Set to "1" to enable the SDL2 blitter. + +This makes pygame use the SDL2 blitter for all alpha +blending. The SDL2 blitter is sometimes faster than +the default blitter but uses a different formula so +the final colours may differ. Must be set before +:func:`pygame.init()` is called. + +| + +:: + + PYGAME_HIDE_SUPPORT_PROMPT - + Set to "1" to hide the prompt. + +This stops the welcome message popping up in the +console that tells you which version of python, +pygame & SDL you are using. Must be set before +importing pygame. + +| + +:: + + PYGAME_FREETYPE - + Set to "1" to enable. + +This switches the pygame.font module to a pure +freetype implementation that bypasses SDL_ttf. +See the font module for why you might want to +do this. Must be set before importing pygame. + +| + +:: + + PYGAME_CAMERA - + Set to "opencv" or "vidcapture" + +Forces the library backend used in the camera +module, overriding the platform defaults. Must +be set before calling :func:`pygame.camera.init()`. + +In pygame 2.0.3, backends can be set programmatically instead, and the old +OpenCV backend has been replaced with one on top of "opencv-python," rather +than the old "highgui" OpenCV port. Also, there is a new native Windows +backend available. + +| +| + +**SDL Environment Variables** + +These variables are defined by SDL. + +For documentation on the environment variables available in +pygame 1 try `here +`__. +For Pygame 2, some selected environment variables are listed below. + +| + +:: + + SDL_VIDEO_CENTERED - + Set to "1" to enable centering the window. + +This will make the pygame window open in the centre of the display. +Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + SDL_VIDEO_WINDOW_POS - + Set to "x,y" to position the top left corner of the window. + +This allows control over the placement of the pygame window within +the display. Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + SDL_VIDEODRIVER - + Set to "drivername" to change the video driver used. + +On some platforms there are multiple video drivers available and +this allows users to pick between them. More information is available +`here `__. Must be set before +calling :func:`pygame.init()` or :func:`pygame.display.init()`. + +| + +:: + + SDL_AUDIODRIVER - + Set to "drivername" to change the audio driver used. + +On some platforms there are multiple audio drivers available and +this allows users to pick between them. More information is available +`here `__. Must be set before +calling :func:`pygame.init()` or :func:`pygame.mixer.init()`. + +| + +:: + + SDL_VIDEO_ALLOW_SCREENSAVER + Set to "1" to allow screensavers while pygame apps are running. + +By default pygame apps disable screensavers while +they are running. Setting this environment variable allows users or +developers to change that and make screensavers run again. + +| + +:: + + SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR + Set to "0" to re-enable the compositor. + +By default SDL tries to disable the X11 compositor for all pygame +apps. This is usually a good thing as it's faster, however if you +have an app which *doesn't* update every frame and are using linux +you may want to disable this bypass. The bypass has reported problems +on KDE linux. This variable is only used on x11/linux platforms. + +| + +:: + + SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS + Set to "1" to allow joysticks to be updated even when the window is out of focus + +By default, when the window is not in focus, input devices do not get +updated. However, using this environment variable it is possible to get +joystick updates even when the window is in the background. Must be set +before calling :func:`pygame.init()` or :func:`pygame.joystick.init()`. diff --git a/docs/ref/rect.rst b/docs/ref/rect.rst new file mode 100644 index 0000000..ce4e605 --- /dev/null +++ b/docs/ref/rect.rst @@ -0,0 +1,604 @@ +.. include:: common.txt + +:mod:`pygame.Rect` +================== + +.. currentmodule:: pygame + +.. class:: Rect + + | :sl:`pygame object for storing rectangular coordinates` + | :sg:`Rect(left, top, width, height) -> Rect` + | :sg:`Rect((left, top), (width, height)) -> Rect` + | :sg:`Rect(object) -> Rect` + + Pygame uses Rect objects to store and manipulate rectangular areas. A Rect + can be created from a combination of left, top, width, and height values. + Rects can also be created from Python objects that are already a Rect or + have an attribute named "rect". + + Any Pygame function that requires a Rect argument also accepts any of these + values to construct a Rect. This makes it easier to create Rects on the fly + as arguments for functions. + + The Rect functions that change the position or size of a Rect return a new + copy of the Rect with the affected changes. The original Rect is not + modified. Some methods have an alternate "in-place" version that returns + None but affects the original Rect. These "in-place" methods are denoted + with the "ip" suffix. + + The Rect object has several virtual attributes which can be used to move and + align the Rect: + + :: + + x,y + top, left, bottom, right + topleft, bottomleft, topright, bottomright + midtop, midleft, midbottom, midright + center, centerx, centery + size, width, height + w,h + + All of these attributes can be assigned to: + + :: + + rect1.right = 10 + rect2.center = (20,30) + + Assigning to size, width or height changes the dimensions of the rectangle; + all other assignments move the rectangle without resizing it. Notice that + some attributes are integers and others are pairs of integers. + + If a Rect has a nonzero width or height, it will return ``True`` for a + nonzero test. Some methods return a Rect with 0 size to represent an invalid + rectangle. A Rect with a 0 size will not collide when using collision + detection methods (e.g. :meth:`collidepoint`, :meth:`colliderect`, etc.). + + The coordinates for Rect objects are all integers. The size values can be + programmed to have negative values, but these are considered illegal Rects + for most operations. + + There are several collision tests between other rectangles. Most python + containers can be searched for collisions against a single Rect. + + The area covered by a Rect does not include the right- and bottom-most edge + of pixels. If one Rect's bottom border is another Rect's top border (i.e., + rect1.bottom=rect2.top), the two meet exactly on the screen but do not + overlap, and ``rect1.colliderect(rect2)`` returns false. + + The Rect object is also iterable: + + :: + + r = Rect(0, 1, 2, 3) + x, y, w, h = r + + .. versionadded:: 1.9.2 + The Rect class can be subclassed. Methods such as ``copy()`` and ``move()`` + will recognize this and return instances of the subclass. + However, the subclass's ``__init__()`` method is not called, + and ``__new__()`` is assumed to take no arguments. So these methods should be + overridden if any extra attributes need to be copied. + + .. method:: copy + + | :sl:`copy the rectangle` + | :sg:`copy() -> Rect` + + Returns a new rectangle having the same position and size as the original. + + New in pygame 1.9 + + .. ## Rect.copy ## + + .. method:: move + + | :sl:`moves the rectangle` + | :sg:`move(x, y) -> Rect` + + Returns a new rectangle that is moved by the given offset. The x and y + arguments can be any integer value, positive or negative. + + .. ## Rect.move ## + + .. method:: move_ip + + | :sl:`moves the rectangle, in place` + | :sg:`move_ip(x, y) -> None` + + Same as the ``Rect.move()`` method, but operates in place. + + .. ## Rect.move_ip ## + + .. method:: inflate + + | :sl:`grow or shrink the rectangle size` + | :sg:`inflate(x, y) -> Rect` + + Returns a new rectangle with the size changed by the given offset. The + rectangle remains centered around its current center. Negative values + will shrink the rectangle. Note, uses integers, if the offset given is + too small(< 2 > -2), center will be off. + + .. ## Rect.inflate ## + + .. method:: inflate_ip + + | :sl:`grow or shrink the rectangle size, in place` + | :sg:`inflate_ip(x, y) -> None` + + Same as the ``Rect.inflate()`` method, but operates in place. + + .. ## Rect.inflate_ip ## + + .. method:: scale_by + + | :sl:`scale the rectangle by given a multiplier` + | :sg:`scale_by(scalar) -> Rect` + | :sg:`scale_by(scalex, scaley) -> Rect` + + Returns a new rectangle with the size scaled by the given multipliers. + The rectangle remains centered around its current center. A single + scalar or separate width and height scalars are allowed. Values above + one will increase the size of the rectangle, whereas values between + zero and one will decrease the size of the rectangle. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.scale_by ## + + .. method:: scale_by_ip + + | :sl:`grow or shrink the rectangle size, in place` + | :sg:`scale_by_ip(scalar) -> None` + | :sg:`scale_by_ip(scalex, scaley) -> None` + + Same as the ``Rect.scale_by()`` method, but operates in place. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.scale_by_ip ## + + .. method:: update + + | :sl:`sets the position and size of the rectangle` + | :sg:`update(left, top, width, height) -> None` + | :sg:`update((left, top), (width, height)) -> None` + | :sg:`update(object) -> None` + + Sets the position and size of the rectangle, in place. See + parameters for :meth:`pygame.Rect` for the parameters of this function. + + .. versionadded:: 2.0.1 + + .. ## Rect.update ## + + .. method:: clamp + + | :sl:`moves the rectangle inside another` + | :sg:`clamp(Rect) -> Rect` + + Returns a new rectangle that is moved to be completely inside the + argument Rect. If the rectangle is too large to fit inside, it is + centered inside the argument Rect, but its size is not changed. + + .. ## Rect.clamp ## + + .. method:: clamp_ip + + | :sl:`moves the rectangle inside another, in place` + | :sg:`clamp_ip(Rect) -> None` + + Same as the ``Rect.clamp()`` method, but operates in place. + + .. ## Rect.clamp_ip ## + + .. method:: clip + + | :sl:`crops a rectangle inside another` + | :sg:`clip(Rect) -> Rect` + + Returns a new rectangle that is cropped to be completely inside the + argument Rect. If the two rectangles do not overlap to begin with, a Rect + with 0 size is returned. + + .. ## Rect.clip ## + + .. method:: clipline + + | :sl:`crops a line inside a rectangle` + | :sg:`clipline(x1, y1, x2, y2) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline(x1, y1, x2, y2) -> ()` + | :sg:`clipline((x1, y1), (x2, y2)) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline((x1, y1), (x2, y2)) -> ()` + | :sg:`clipline((x1, y1, x2, y2)) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline((x1, y1, x2, y2)) -> ()` + | :sg:`clipline(((x1, y1), (x2, y2))) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline(((x1, y1), (x2, y2))) -> ()` + + Returns the coordinates of a line that is cropped to be completely inside + the rectangle. If the line does not overlap the rectangle, then an empty + tuple is returned. + + The line to crop can be any of the following formats (floats can be used + in place of ints, but they will be truncated): + + - four ints + - 2 lists/tuples/Vector2s of 2 ints + - a list/tuple of four ints + - a list/tuple of 2 lists/tuples/Vector2s of 2 ints + + :returns: a tuple with the coordinates of the given line cropped to be + completely inside the rectangle is returned, if the given line does + not overlap the rectangle, an empty tuple is returned + :rtype: tuple(tuple(int, int), tuple(int, int)) or () + + :raises TypeError: if the line coordinates are not given as one of the + above described line formats + + .. note :: + This method can be used for collision detection between a rect and a + line. See example code below. + + .. note :: + The ``rect.bottom`` and ``rect.right`` attributes of a + :mod:`pygame.Rect` always lie one pixel outside of its actual border. + + :: + + # Example using clipline(). + clipped_line = rect.clipline(line) + + if clipped_line: + # If clipped_line is not an empty tuple then the line + # collides/overlaps with the rect. The returned value contains + # the endpoints of the clipped line. + start, end = clipped_line + x1, y1 = start + x2, y2 = end + else: + print("No clipping. The line is fully outside the rect.") + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. versionadded:: 2.0.0 + + .. ## Rect.clipline ## + + .. method:: union + + | :sl:`joins two rectangles into one` + | :sg:`union(Rect) -> Rect` + + Returns a new rectangle that completely covers the area of the two + provided rectangles. There may be area inside the new Rect that is not + covered by the originals. + + .. ## Rect.union ## + + .. method:: union_ip + + | :sl:`joins two rectangles into one, in place` + | :sg:`union_ip(Rect) -> None` + + Same as the ``Rect.union()`` method, but operates in place. + + .. ## Rect.union_ip ## + + .. method:: unionall + + | :sl:`the union of many rectangles` + | :sg:`unionall(Rect_sequence) -> Rect` + + Returns the union of one rectangle with a sequence of many rectangles. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.unionall ## + + .. method:: unionall_ip + + | :sl:`the union of many rectangles, in place` + | :sg:`unionall_ip(Rect_sequence) -> None` + + The same as the ``Rect.unionall()`` method, but operates in place. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.unionall_ip ## + + .. method:: fit + + | :sl:`resize and move a rectangle with aspect ratio` + | :sg:`fit(Rect) -> Rect` + + Returns a new rectangle that is moved and resized to fit another. The + aspect ratio of the original Rect is preserved, so the new rectangle may + be smaller than the target in either width or height. + + .. ## Rect.fit ## + + .. method:: normalize + + | :sl:`correct negative sizes` + | :sg:`normalize() -> None` + + This will flip the width or height of a rectangle if it has a negative + size. The rectangle will remain in the same place, with only the sides + swapped. + + .. ## Rect.normalize ## + + .. method:: contains + + | :sl:`test if one rectangle is inside another` + | :sg:`contains(Rect) -> bool` + + Returns true when the argument is completely inside the Rect. + + .. ## Rect.contains ## + + .. method:: collidepoint + + | :sl:`test if a point is inside a rectangle` + | :sg:`collidepoint(x, y) -> bool` + | :sg:`collidepoint((x,y)) -> bool` + + Returns true if the given point is inside the rectangle. A point along + the right or bottom edge is not considered to be inside the rectangle. + + .. note :: + For collision detection between a rect and a line the :meth:`clipline` + method can be used. + + .. ## Rect.collidepoint ## + + .. method:: colliderect + + | :sl:`test if two rectangles overlap` + | :sg:`colliderect(Rect) -> bool` + + Returns true if any portion of either rectangle overlap (except the + top+bottom or left+right edges). + + .. note :: + For collision detection between a rect and a line the :meth:`clipline` + method can be used. + + .. ## Rect.colliderect ## + + .. method:: collidelist + + | :sl:`test if one rectangle in a list intersects` + | :sg:`collidelist(list) -> index` + + Test whether the rectangle collides with any in a sequence of rectangles. + The index of the first collision found is returned. If no collisions are + found an index of -1 is returned. + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.collidelist ## + + .. method:: collidelistall + + | :sl:`test if all rectangles in a list intersect` + | :sg:`collidelistall(list) -> indices` + + Returns a list of all the indices that contain rectangles that collide + with the Rect. If no intersecting rectangles are found, an empty list is + returned. + + Not only Rects are valid arguments, but these are all valid calls: + + .. code-block:: python + + Rect = pygame.Rect + r = Rect(0, 0, 10, 10) + + list_of_rects = [Rect(1, 1, 1, 1), Rect(2, 2, 2, 2)] + indices0 = r.collidelistall(list_of_rects) + + list_of_lists = [[1, 1, 1, 1], [2, 2, 2, 2]] + indices1 = r.collidelistall(list_of_lists) + + list_of_tuples = [(1, 1, 1, 1), (2, 2, 2, 2)] + indices2 = r.collidelistall(list_of_tuples) + + list_of_double_tuples = [((1, 1), (1, 1)), ((2, 2), (2, 2))] + indices3 = r.collidelistall(list_of_double_tuples) + + class ObjectWithRectAttribute(object): + def __init__(self, r): + self.rect = r + + list_of_object_with_rect_attribute = [ + ObjectWithRectAttribute(Rect(1, 1, 1, 1)), + ObjectWithRectAttribute(Rect(2, 2, 2, 2)), + ] + indices4 = r.collidelistall(list_of_object_with_rect_attribute) + + class ObjectWithCallableRectAttribute(object): + def __init__(self, r): + self._rect = r + + def rect(self): + return self._rect + + list_of_object_with_callable_rect = [ + ObjectWithCallableRectAttribute(Rect(1, 1, 1, 1)), + ObjectWithCallableRectAttribute(Rect(2, 2, 2, 2)), + ] + indices5 = r.collidelistall(list_of_object_with_callable_rect) + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.collidelistall ## + + .. method:: collideobjects + + | :sl:`test if any object in a list intersects` + | :sg:`collideobjects(rect_list) -> object` + | :sg:`collideobjects(obj_list, key=func) -> object` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave collideobjects feedback with authors `_ + + Test whether the rectangle collides with any object in the sequence. + The object of the first collision found is returned. If no collisions are + found then ``None`` is returned + + If key is given, then it should be a method taking an object from the list + as input and returning a rect like object e.g. ``lambda obj: obj.rectangle``. + If an object has multiple attributes of type Rect then key could return one + of them. + + .. code-block:: python + + r = Rect(1, 1, 10, 10) + + rects = [ + Rect(1, 1, 10, 10), + Rect(5, 5, 10, 10), + Rect(15, 15, 1, 1), + Rect(2, 2, 1, 1), + ] + + result = r.collideobjects(rects) # -> + print(result) + + class ObjectWithSomRectAttribute: + def __init__(self, name, collision_box, draw_rect): + self.name = name + self.draw_rect = draw_rect + self.collision_box = collision_box + + def __repr__(self): + return f'<{self.__class__.__name__}("{self.name}", {list(self.collision_box)}, {list(self.draw_rect)})>' + + objects = [ + ObjectWithSomRectAttribute("A", Rect(15, 15, 1, 1), Rect(150, 150, 50, 50)), + ObjectWithSomRectAttribute("B", Rect(1, 1, 10, 10), Rect(300, 300, 50, 50)), + ObjectWithSomRectAttribute("C", Rect(5, 5, 10, 10), Rect(200, 500, 50, 50)), + ] + + # collision = r.collideobjects(objects) # this does not work because the items in the list are no Rect like object + collision = r.collideobjects( + objects, key=lambda o: o.collision_box + ) # -> + print(collision) + + screen_rect = r.collideobjects(objects, key=lambda o: o.draw_rect) # -> None + print(screen_rect) + + .. versionadded:: 2.1.3 + + .. ## Rect.collideobjects ## + + .. method:: collideobjectsall + + | :sl:`test if all objects in a list intersect` + | :sg:`collideobjectsall(rect_list) -> objects` + | :sg:`collideobjectsall(obj_list, key=func) -> objects` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave collideobjectsall feedback with authors `_ + + Returns a list of all the objects that contain rectangles that collide + with the Rect. If no intersecting objects are found, an empty list is + returned. + + If key is given, then it should be a method taking an object from the list + as input and returning a rect like object e.g. ``lambda obj: obj.rectangle``. + If an object has multiple attributes of type Rect then key could return one + of them. + + .. code-block:: python + + r = Rect(1, 1, 10, 10) + + rects = [ + Rect(1, 1, 10, 10), + Rect(5, 5, 10, 10), + Rect(15, 15, 1, 1), + Rect(2, 2, 1, 1), + ] + + result = r.collideobjectsall( + rects + ) # -> [, , ] + print(result) + + class ObjectWithSomRectAttribute: + def __init__(self, name, collision_box, draw_rect): + self.name = name + self.draw_rect = draw_rect + self.collision_box = collision_box + + def __repr__(self): + return f'<{self.__class__.__name__}("{self.name}", {list(self.collision_box)}, {list(self.draw_rect)})>' + + objects = [ + ObjectWithSomRectAttribute("A", Rect(1, 1, 10, 10), Rect(300, 300, 50, 50)), + ObjectWithSomRectAttribute("B", Rect(5, 5, 10, 10), Rect(200, 500, 50, 50)), + ObjectWithSomRectAttribute("C", Rect(15, 15, 1, 1), Rect(150, 150, 50, 50)), + ] + + # collisions = r.collideobjectsall(objects) # this does not work because ObjectWithSomRectAttribute is not a Rect like object + collisions = r.collideobjectsall( + objects, key=lambda o: o.collision_box + ) # -> [, ] + print(collisions) + + screen_rects = r.collideobjectsall(objects, key=lambda o: o.draw_rect) # -> [] + print(screen_rects) + + .. versionadded:: 2.1.3 + + .. ## Rect.collideobjectsall ## + + .. method:: collidedict + + | :sl:`test if one rectangle in a dictionary intersects` + | :sg:`collidedict(dict) -> (key, value)` + | :sg:`collidedict(dict) -> None` + | :sg:`collidedict(dict, use_values=0) -> (key, value)` + | :sg:`collidedict(dict, use_values=0) -> None` + + Returns the first key and value pair that intersects with the calling + Rect object. If no collisions are found, ``None`` is returned. If + ``use_values`` is 0 (default) then the dict's keys will be used in the + collision detection, otherwise the dict's values will be used. + + .. note :: + Rect objects cannot be used as keys in a dictionary (they are not + hashable), so they must be converted to a tuple. + e.g. ``rect.collidedict({tuple(key_rect) : value})`` + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.collidedict ## + + .. method:: collidedictall + + | :sl:`test if all rectangles in a dictionary intersect` + | :sg:`collidedictall(dict) -> [(key, value), ...]` + | :sg:`collidedictall(dict, use_values=0) -> [(key, value), ...]` + + Returns a list of all the key and value pairs that intersect with the + calling Rect object. If no collisions are found an empty list is returned. + If ``use_values`` is 0 (default) then the dict's keys will be used in the + collision detection, otherwise the dict's values will be used. + + .. note :: + Rect objects cannot be used as keys in a dictionary (they are not + hashable), so they must be converted to a tuple. + e.g. ``rect.collidedictall({tuple(key_rect) : value})`` + + .. versionchanged:: 2.5.0 Added support for keyword arguments. + + .. ## Rect.collidedictall ## + + .. ## pygame.Rect ## diff --git a/docs/ref/scrap.rst b/docs/ref/scrap.rst new file mode 100644 index 0000000..1aac5d0 --- /dev/null +++ b/docs/ref/scrap.rst @@ -0,0 +1,240 @@ +.. include:: common.txt + +:mod:`pygame.scrap` +=================== + +.. module:: pygame.scrap + :synopsis: pygame module for clipboard support. + +| :sl:`pygame module for clipboard support.` + +**EXPERIMENTAL!**: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release. + +The scrap module is for transferring data to/from the clipboard. This allows +for cutting and pasting data between pygame and other applications. Some basic +data (MIME) types are defined and registered: + +:: + + pygame string + constant value description + -------------------------------------------------- + SCRAP_TEXT "text/plain" plain text + SCRAP_BMP "image/bmp" BMP encoded image data + SCRAP_PBM "image/pbm" PBM encoded image data + SCRAP_PPM "image/ppm" PPM encoded image data + +``pygame.SCRAP_PPM``, ``pygame.SCRAP_PBM`` and ``pygame.SCRAP_BMP`` are +suitable for surface buffers to be shared with other applications. +``pygame.SCRAP_TEXT`` is an alias for the plain text clipboard type. + +Depending on the platform, additional types are automatically registered when +data is placed into the clipboard to guarantee a consistent sharing behaviour +with other applications. The following listed types can be used as strings to +be passed to the respective :mod:`pygame.scrap` module functions. + +For **Windows** platforms, these additional types are supported automatically +and resolve to their internal definitions: + +:: + + "text/plain;charset=utf-8" UTF-8 encoded text + "audio/wav" WAV encoded audio + "image/tiff" TIFF encoded image data + +For **X11** platforms, these additional types are supported automatically and +resolve to their internal definitions: + +:: + + "text/plain;charset=utf-8" UTF-8 encoded text + "UTF8_STRING" UTF-8 encoded text + "COMPOUND_TEXT" COMPOUND text + +User defined types can be used, but the data might not be accessible by other +applications unless they know what data type to look for. +Example: Data placed into the clipboard by +``pygame.scrap.put("my_data_type", byte_data)`` can only be accessed by +applications which query the clipboard for the ``"my_data_type"`` data type. + +For an example of how the scrap module works refer to the examples page +(:func:`pygame.examples.scrap_clipboard.main`) or the code directly in GitHub +(`pygame/examples/scrap_clipboard.py `_). + +.. versionadded:: 1.8 + +.. note:: + The scrap module is currently only supported for Windows, X11 and Mac OS X. + On Mac OS X only text works at the moment - other types may be supported in + future releases. + +.. function:: init + + | :sl:`Initializes the scrap module.` + | :sg:`init() -> None` + + Initialize the scrap module. + + :raises pygame.error: if unable to initialize scrap module + + .. note:: The scrap module requires :func:`pygame.display.set_mode()` be + called before being initialized. + + .. ## pygame.scrap.init ## + +.. function:: get_init + + | :sl:`Returns True if the scrap module is currently initialized.` + | :sg:`get_init() -> bool` + + Gets the scrap module's initialization state. + + :returns: ``True`` if the :mod:`pygame.scrap` module is currently + initialized, ``False`` otherwise + :rtype: bool + + .. versionadded:: 1.9.5 + + .. ## pygame.scrap.get_init ## + +.. function:: get + + | :sl:`Gets the data for the specified type from the clipboard.` + | :sg:`get(type) -> bytes | None` + + Retrieves the data for the specified type from the clipboard. The data is + returned as a byte string and might need further processing (such as + decoding to Unicode). + + :param string type: data type to retrieve from the clipboard + + :returns: data (bytes object) for the given type identifier or ``None`` if + no data for the given type is available + :rtype: bytes | None + + :: + + text = pygame.scrap.get(pygame.SCRAP_TEXT) + if text: + print("There is text in the clipboard.") + else: + print("There does not seem to be text in the clipboard.") + + .. ## pygame.scrap.get ## + +.. function:: get_types + + | :sl:`Gets a list of the available clipboard types.` + | :sg:`get_types() -> list` + + Gets a list of data type string identifiers for the data currently + available on the clipboard. Each identifier can be used in the + :func:`pygame.scrap.get()` method to get the clipboard content of the + specific type. + + :returns: list of strings of the available clipboard data types, if there + is no data in the clipboard an empty list is returned + :rtype: list + + :: + + for t in pygame.scrap.get_types(): + if "text" in t: + # There is some content with the word "text" in its type string. + print(pygame.scrap.get(t)) + + .. ## pygame.scrap.get_types ## + +.. function:: put + + | :sl:`Places data into the clipboard.` + | :sg:`put(type, data) -> None` + + Places data for a given clipboard type into the clipboard. The data must + be a string buffer. The type is a string identifying the type of data to be + placed into the clipboard. This can be one of the predefined + ``pygame.SCRAP_PBM``, ``pygame.SCRAP_PPM``, ``pygame.SCRAP_BMP`` or + ``pygame.SCRAP_TEXT`` values or a user defined string identifier. + + :param string type: type identifier of the data to be placed into the + clipboard + :param data: data to be place into the clipboard, a bytes object + :type data: bytes + + :raises pygame.error: if unable to put the data into the clipboard + + :: + + with open("example.bmp", "rb") as fp: + pygame.scrap.put(pygame.SCRAP_BMP, fp.read()) + # The image data is now on the clipboard for other applications to access + # it. + pygame.scrap.put(pygame.SCRAP_TEXT, b"A text to copy") + pygame.scrap.put("Plain text", b"Data for user defined type 'Plain text'") + + .. ## pygame.scrap.put ## + +.. function:: contains + + | :sl:`Checks whether data for a given type is available in the clipboard.` + | :sg:`contains(type) -> bool` + + Checks whether data for the given type is currently available in the + clipboard. + + :param string type: data type to check availability of + + :returns: ``True`` if data for the passed type is available in the + clipboard, ``False`` otherwise + :rtype: bool + + :: + + if pygame.scrap.contains(pygame.SCRAP_TEXT): + print("There is text in the clipboard.") + if pygame.scrap.contains("own_data_type"): + print("There is stuff in the clipboard.") + + .. ## pygame.scrap.contains ## + +.. function:: lost + + | :sl:`Indicates if the clipboard ownership has been lost by the pygame application.` + | :sg:`lost() -> bool` + + Indicates if the clipboard ownership has been lost by the pygame + application. + + :returns: ``True``, if the clipboard ownership has been lost by the pygame + application, ``False`` if the pygame application still owns the clipboard + :rtype: bool + + :: + + if pygame.scrap.lost(): + print("The clipboard is in use by another application.") + + .. ## pygame.scrap.lost ## + +.. function:: set_mode + + | :sl:`Sets the clipboard access mode.` + | :sg:`set_mode(mode) -> None` + + Sets the access mode for the clipboard. This is only of interest for X11 + environments where clipboard modes ``pygame.SCRAP_SELECTION`` (for mouse + selections) and ``pygame.SCRAP_CLIPBOARD`` (for the clipboard) are + available. Setting the mode to ``pygame.SCRAP_SELECTION`` in other + environments will not change the mode from ``pygame.SCRAP_CLIPBOARD``. + + :param mode: access mode, supported values are ``pygame.SCRAP_CLIPBOARD`` + and ``pygame.SCRAP_SELECTION`` (``pygame.SCRAP_SELECTION`` only has an + effect when used on X11 platforms) + + :raises ValueError: if the ``mode`` parameter is not + ``pygame.SCRAP_CLIPBOARD`` or ``pygame.SCRAP_SELECTION`` + + .. ## pygame.scrap.set_mode ## + +.. ## pygame.scrap ## diff --git a/docs/ref/sdl2_controller.rst b/docs/ref/sdl2_controller.rst new file mode 100644 index 0000000..dbea64a --- /dev/null +++ b/docs/ref/sdl2_controller.rst @@ -0,0 +1,290 @@ +.. include:: common.txt + +:mod:`pygame._sdl2.controller` +============================== + +.. module:: pygame._sdl2.controller + :synopsis: pygame module to work with controllers + +| :sl:`Pygame module to work with controllers.` + +.. note:: + Use import pygame._sdl2.controller before using this module. + +This module offers control over common controller types like the dualshock 4 or +the xbox 360 controllers: They have two analog sticks, two triggers, two shoulder buttons, +a dpad, 4 buttons on the side, 2 (or 3) buttons in the middle. + +Pygame uses xbox controllers naming conventions (like a, b, x, y for buttons) but +they always refer to the same buttons. For example ``CONTROLLER_BUTTON_X`` is +always the leftmost button of the 4 buttons on the right. + +Controllers can generate the following events:: + + CONTROLLERAXISMOTION, CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP, + CONTROLLERDEVICEREMAPPED, CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED + +Additionally if pygame is built with SDL 2.0.14 or higher the following events can also be generated +(to get the version of sdl pygame is built with use :meth:`pygame.version.SDL`):: + + CONTROLLERTOUCHPADDOWN, CONTROLLERTOUCHPADMOTION, CONTROLLERTOUCHPADUP + +These events can be enabled/disabled by :meth:`pygame._sdl2.controller.set_eventstate` +Note that controllers can generate joystick events as well. This function only toggles +events related to controllers. + +.. note:: + See the :mod:`pygame.joystick` for a more versatile but more advanced api. + +.. versionadded:: 2 This module requires SDL2. + +.. function:: init + + | :sl:`initialize the controller module` + | :sg:`init() -> None` + + Initialize the controller module. + + .. ## pygame._sdl2.controller.init ## + +.. function:: quit + + | :sl:`Uninitialize the controller module.` + | :sg:`quit() -> None` + + Uninitialize the controller module. + + .. ## pygame._sdl2.controller.quit ## + +.. function:: get_init + + | :sl:`Returns True if the controller module is initialized.` + | :sg:`get_init() -> bool` + + Test if ``pygame._sdl2.controller.init()`` was called. + + .. ## pygame._sdl2.controller.get_init ## + +.. function:: set_eventstate + + | :sl:`Sets the current state of events related to controllers` + | :sg:`set_eventstate(state) -> None` + + Enable or disable events connected to controllers. + + .. note:: + Controllers can still generate joystick events, which will not be toggled by this function. + + .. versionchanged:: 2.0.2: Changed return type from int to None + + .. ## pygame._sdl2.controller.set_eventstate ## + +.. function:: get_eventstate + + | :sl:`Gets the current state of events related to controllers` + | :sg:`get_eventstate() -> bool` + + Returns the current state of events related to controllers, True meaning + events will be posted. + + .. versionadded:: 2.0.2 + + .. ## pygame._sdl2.controller.get_eventstate ## + +.. function:: get_count + + | :sl:`Get the number of joysticks connected` + | :sg:`get_count() -> int` + + Get the number of joysticks connected. + + .. ## pygame._sdl2.controller.get_count ## + +.. function:: is_controller + + | :sl:`Check if the given joystick is supported by the game controller interface` + | :sg:`is_controller(index) -> bool` + + Returns True if the index given can be used to create a controller object. + + .. ## pygame._sdl2.controller.is_controller ## + +.. function:: name_forindex + + | :sl:`Get the name of the controller` + | :sg:`name_forindex(index) -> name or None` + + Returns the name of controller, or None if there's no name or the + index is invalid. + + .. ## pygame._sdl2.controller.name_forindex ## + +.. class:: Controller + + | :sl:`Create a new Controller object.` + | :sg:`Controller(index) -> Controller` + + Create a new Controller object. Index should be integer between + 0 and ``pygame._sdl2.controller.get_count()``. Controllers also + can be created from a ``pygame.joystick.Joystick`` using + ``pygame._sdl2.controller.from_joystick``. Controllers are + initialized on creation. + + .. method:: quit + + | :sl:`uninitialize the Controller` + | :sg:`quit() -> None` + + Close a Controller object. After this the pygame event queue will no longer + receive events from the device. + + It is safe to call this more than once. + + .. ## Controller.quit ## + + .. method:: get_init + + | :sl:`check if the Controller is initialized` + | :sg:`get_init() -> bool` + + Returns True if the Controller object is currently initialised. + + .. ## Controller.get_init ## + + .. staticmethod:: from_joystick + + | :sl:`Create a Controller from a pygame.joystick.Joystick object` + | :sg:`from_joystick(joystick) -> Controller` + + Create a Controller object from a ``pygame.joystick.Joystick`` object + + .. ## Controller.from_joystick ## + + .. method:: attached + + | :sl:`Check if the Controller has been opened and is currently connected.` + | :sg:`attached() -> bool` + + Returns True if the Controller object is opened and connected. + + .. ## Controller.attached ## + + .. method:: as_joystick + + | :sl:`Returns a pygame.joystick.Joystick() object` + | :sg:`as_joystick() -> Joystick object` + + Returns a pygame.joystick.Joystick() object created from this controller's index + + .. ## Controller.as_joystick ## + + .. method:: get_axis + + | :sl:`Get the current state of a joystick axis` + | :sg:`get_axis(axis) -> int` + + Get the current state of a trigger or joystick axis. + The axis argument must be one of the following constants:: + + CONTROLLER_AXIS_LEFTX, CONTROLLER_AXIS_LEFTY, + CONTROLLER_AXIS_RIGHTX, CONTROLLER_AXIS_RIGHTY, + CONTROLLER_AXIS_TRIGGERLEFT, CONTROLLER_AXIS_TRIGGERRIGHT + + Joysticks can return a value between -32768 and 32767. Triggers however + can only return a value between 0 and 32768. + + .. ## Controller.get_axis ## + + .. method:: get_button + + | :sl:`Get the current state of a button` + | :sg:`get_button(button) -> bool` + + Get the current state of a button, True meaning it is pressed down. + The button argument must be one of the following constants:: + + CONTROLLER_BUTTON_A, CONTROLLER_BUTTON_B, + CONTROLLER_BUTTON_X, CONTROLLER_BUTTON_Y + CONTROLLER_BUTTON_DPAD_UP, CONTROLLER_BUTTON_DPAD_DOWN, + CONTROLLER_BUTTON_DPAD_LEFT, CONTROLLER_BUTTON_DPAD_RIGHT, + CONTROLLER_BUTTON_LEFTSHOULDER, CONTROLLER_BUTTON_RIGHTSHOULDER, + CONTROLLER_BUTTON_LEFTSTICK, CONTROLLER_BUTTON_RIGHTSTICK, + CONTROLLER_BUTTON_BACK, CONTROLLER_BUTTON_GUIDE, + CONTROLLER_BUTTON_START + + + .. ## Controller.get_button ## + + .. method:: get_mapping + + | :sl:`Get the mapping assigned to the controller` + | :sg:`get_mapping() -> mapping` + + Returns a dict containing the mapping of the Controller. For more + information see :meth:`Controller.set_mapping()` + + .. versionchanged:: 2.0.2: Return type changed from ``str`` to ``dict`` + + .. ## Contorller.get_mapping ## + + .. method:: set_mapping + + | :sl:`Assign a mapping to the controller` + | :sg:`set_mapping(mapping) -> int` + + Rebind buttons, axes, triggers and dpads. The mapping should be a + dict containing all buttons, hats and axes. The easiest way to get this + is to use the dict returned by :meth:`Controller.get_mapping`. To edit + this mapping assign a value to the original button. The value of the + dictionary must be a button, hat or axis represented in the following way: + + * For a button use: bX where X is the index of the button. + * For a hat use: hX.Y where X is the index and the Y is the direction (up: 1, right: 2, down: 3, left: 4). + * For an axis use: aX where x is the index of the axis. + + An example of mapping:: + + mapping = controller.get_mapping() # Get current mapping + mapping["a"] = "b3" # Remap button a to y + mapping["y"] = "b0" # Remap button y to a + controller.set_mapping(mapping) # Set the mapping + + + The function will return 1 if a new mapping is added or 0 if an existing one is updated. + + .. versionchanged:: 2.0.2: Renamed from ``add_mapping`` to ``set_mapping`` + .. versionchanged:: 2.0.2: Argument type changed from ``str`` to ``dict`` + + .. ## Contorller.set_mapping ## + + .. method:: rumble + + | :sl:`Start a rumbling effect` + | :sg:`rumble(low_frequency, high_frequency, duration) -> bool` + + Start a rumble effect on the controller, with the specified strength ranging + from 0 to 1. Duration is length of the effect, in ms. Setting the duration + to 0 will play the effect until another one overwrites it or + :meth:`Controller.stop_rumble` is called. If an effect is already + playing, then it will be overwritten. + + Returns True if the rumble was played successfully or False if the + controller does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + + .. versionadded:: 2.0.2 + + .. ## Contorller.rumble ## + + .. method:: stop_rumble + + | :sl:`Stop any rumble effect playing` + | :sg:`stop_rumble() -> None` + + Stops any rumble effect playing on the controller. See + :meth:`Controller.rumble` for more information. + + .. versionadded:: 2.0.2 + + .. ## Contorller.stop_rumble ## + +.. ## pygame._sdl2.controller ## diff --git a/docs/ref/sdl2_video.rst b/docs/ref/sdl2_video.rst new file mode 100644 index 0000000..e273363 --- /dev/null +++ b/docs/ref/sdl2_video.rst @@ -0,0 +1,334 @@ +.. include:: common.txt + +:mod:`pygame.sdl2_video` +======================== + +.. module:: pygame._sdl2.video + :synopsis: Experimental pygame module for porting new SDL video systems + +.. warning:: + This module isn't ready for prime time yet, it's still in development. + These docs are primarily meant to help the pygame developers and super-early adopters + who are in communication with the developers. This API will change. + +| :sl:`Experimental pygame module for porting new SDL video systems` + +.. class:: Window + + | :sl:`pygame object that represents a window` + | :sg:`Window(title="pygame", size=(640, 480), position=None, fullscreen=False, fullscreen_desktop=False, keywords) -> Window` + + .. classmethod:: from_display_module + + | :sl:`Creates window using window created by pygame.display.set_mode().` + | :sg:`from_display_module() -> Window` + + .. classmethod:: from_window + + | :sl:`Create Window from another window. Could be from another UI toolkit.` + | :sg:`from_window(other) -> Window` + + .. attribute:: grab + + | :sl:`Gets or sets whether the mouse is confined to the window.` + | :sg:`grab -> bool` + + .. attribute:: relative_mouse + + | :sl:`Gets or sets the window's relative mouse motion state.` + | :sg:`relative_mouse -> bool` + + .. method:: set_windowed + + | :sl:`Enable windowed mode (exit fullscreen).` + | :sg:`set_windowed() -> None` + + .. method:: set_fullscreen + + | :sl:`Enter fullscreen.` + | :sg:`set_fullscreen(desktop=False) -> None` + + .. attribute:: title + + | :sl:`Gets or sets whether the window title.` + | :sg:`title -> string` + + .. method:: destroy + + | :sl:`Destroys the window.` + | :sg:`destroy() -> None` + + .. method:: hide + + | :sl:`Hide the window.` + | :sg:`hide() -> None` + + .. method:: show + + | :sl:`Show the window.` + | :sg:`show() -> None` + + .. method:: focus + + | :sl:`Raise the window above other windows and set the input focus. The "input_only" argument is only supported on X11.` + | :sg:`focus(input_only=False) -> None` + + .. method:: restore + + | :sl:`Restore the size and position of a minimized or maximized window.` + | :sg:`restore() -> None` + + .. method:: maximize + + | :sl:`Maximize the window.` + | :sg:`maximize() -> None` + + .. method:: minimize + + | :sl:`Minimize the window.` + | :sg:`maximize() -> None` + + .. attribute:: resizable + + | :sl:`Gets and sets whether the window is resizable.` + | :sg:`resizable -> bool` + + .. attribute:: borderless + + | :sl:`Add or remove the border from the window.` + | :sg:`borderless -> bool` + + .. method:: set_icon + + | :sl:`Set the icon for the window.` + | :sg:`set_icon(surface) -> None` + + .. attribute:: id + + | :sl:`Get the unique window ID. *Read-only*` + | :sg:`id -> int` + + .. attribute:: size + + | :sl:`Gets and sets the window size.` + | :sg:`size -> (int, int)` + + .. attribute:: position + + | :sl:`Gets and sets the window position.` + | :sg:`position -> (int, int) or WINDOWPOS_CENTERED or WINDOWPOS_UNDEFINED` + + .. attribute:: opacity + + | :sl:`Gets and sets the window opacity. Between 0.0 (fully transparent) and 1.0 (fully opaque).` + | :sg:`opacity -> float` + + .. attribute:: display_index + + | :sl:`Get the index of the display that owns the window. *Read-only*` + | :sg:`display_index -> int` + + .. method:: set_modal_for + + | :sl:`Set the window as a modal for a parent window. This function is only supported on X11.` + | :sg:`set_modal_for(Window) -> None` + +.. class:: Texture + + | :sl:`pygame object that representing a Texture.` + | :sg:`Texture(renderer, size, depth=0, static=False, streaming=False, target=False) -> Texture` + + .. staticmethod:: from_surface + + | :sl:`Create a texture from an existing surface.` + | :sg:`from_surface(renderer, surface) -> Texture` + + .. attribute:: renderer + + | :sl:`Gets the renderer associated with the Texture. *Read-only*` + | :sg:`renderer -> Renderer` + + .. attribute:: width + + | :sl:`Gets the width of the Texture. *Read-only*` + | :sg:`width -> int` + + .. attribute:: height + + | :sl:`Gets the height of the Texture. *Read-only*` + | :sg:`height -> int` + + .. attribute:: alpha + + | :sl:`Gets and sets an additional alpha value multiplied into render copy operations.` + | :sg:`alpha -> int` + + .. attribute:: blend_mode + + | :sl:`Gets and sets the blend mode for the Texture.` + | :sg:`blend_mode -> int` + + .. attribute:: color + + | :sl:`Gets and sets an additional color value multiplied into render copy operations.` + | :sg:`color -> color` + + .. method:: get_rect + + | :sl:`Get the rectangular area of the texture.` + | :sg:`get_rect(**kwargs) -> Rect` + + .. method:: draw + + | :sl:`Copy a portion of the texture to the rendering target.` + | :sg:`draw(srcrect=None, dstrect=None, angle=0, origin=None, flip_x=False, flip_y=False) -> None` + + .. method:: update + + | :sl:`Update the texture with a Surface. WARNING: Slow operation, use sparingly.` + | :sg:`update(surface, area=None) -> None` + +.. class:: Image + + | :sl:`Easy way to use a portion of a Texture without worrying about srcrect all the time.` + | :sg:`Image(textureOrImage, srcrect=None) -> Image` + + .. method:: get_rect + + | :sl:`Get the rectangular area of the Image.` + | :sg:`get_rect() -> Rect` + + .. method:: draw + + | :sl:`Copy a portion of the Image to the rendering target.` + | :sg:`draw(srcrect=None, dstrect=None) -> None` + + .. attribute:: angle + + | :sl:`Gets and sets the angle the Image draws itself with.` + | :sg:`angle -> float` + + .. attribute:: origin + + | :sl:`Gets and sets the origin. Origin=None means the Image will be rotated around its center.` + | :sg:`origin -> (float, float) or None.` + + .. attribute:: flip_x + + | :sl:`Gets and sets whether the Image is flipped on the x axis.` + | :sg:`flip_x -> bool` + + .. attribute:: flip_y + + | :sl:`Gets and sets whether the Image is flipped on the y axis.` + | :sg:`flip_y -> bool` + + .. attribute:: color + + | :sl:`Gets and sets the Image color modifier.` + | :sg:`color -> Color` + + .. attribute:: alpha + + | :sl:`Gets and sets the Image alpha modifier.` + | :sg:`alpha -> float` + + .. attribute:: blend_mode + + | :sl:`Gets and sets the blend mode for the Image.` + | :sg:`blend_mode -> int` + + .. attribute:: texture + + | :sl:`Gets and sets the Texture the Image is based on.` + | :sg:`texture -> Texture` + + .. attribute:: srcrect + + | :sl:`Gets and sets the Rect the Image is based on.` + | :sg:`srcrect -> Rect` + +.. class:: Renderer + + | :sl:`Create a 2D rendering context for a window.` + | :sg:`Renderer(window, index=-1, accelerated=-1, vsync=False, target_texture=False) -> Renderer` + + .. classmethod:: from_window + + | :sl:`Easy way to create a Renderer.` + | :sg:`from_window(window) -> Renderer` + + .. attribute:: draw_blend_mode + + | :sl:`Gets and sets the blend mode used by the drawing functions.` + | :sg:`draw_blend_mode -> int` + + .. attribute:: draw_color + + | :sl:`Gets and sets the color used by the drawing functions.` + | :sg:`draw_color -> Color` + + .. method:: clear + + | :sl:`Clear the current rendering target with the drawing color.` + | :sg:`clear() -> None` + + .. method:: present + + | :sl:`Updates the screen with any new rendering since previous call.` + | :sg:`present() -> None` + + .. method:: get_viewport + + | :sl:`Returns the drawing area on the target.` + | :sg:`get_viewport() -> Rect` + + .. method:: set_viewport + + | :sl:`Set the drawing area on the target. If area is None, the entire target will be used.` + | :sg:`set_viewport(area) -> None` + + .. attribute:: logical_size + + | :sl:`Gets and sets the logical size.` + | :sg:`logical_size -> (int width, int height)` + + .. attribute:: scale + + | :sl:`Gets and sets the scale.` + | :sg:`scale -> (float x_scale, float y_scale)` + + .. attribute:: target + + | :sl:`Gets and sets the render target. None represents the default target (the renderer).` + | :sg:`target -> Texture or None` + + .. method:: blit + + | :sl:`For compatibility purposes. Textures created by different Renderers cannot be shared!` + | :sg:`blit(source, dest, area=None, special_flags=0)-> Rect` + + .. method:: draw_line + + | :sl:`Draws a line.` + | :sg:`draw_line(p1, p2) -> None` + + .. method:: draw_point + + | :sl:`Draws a point.` + | :sg:`draw_point(point) -> None` + + .. method:: draw_rect + + | :sl:`Draws a rectangle.` + | :sg:`draw_rect(rect)-> None` + + .. method:: fill_rect + + | :sl:`Fills a rectangle.` + | :sg:`fill_rect(rect)-> None` + + .. method:: to_surface + + | :sl:`Read pixels from current render target and create a pygame.Surface. WARNING: Slow operation, use sparingly.` + | :sg:`to_surface(surface=None, area=None)-> Surface` \ No newline at end of file diff --git a/docs/ref/sndarray.rst b/docs/ref/sndarray.rst new file mode 100644 index 0000000..2a17764 --- /dev/null +++ b/docs/ref/sndarray.rst @@ -0,0 +1,95 @@ +.. include:: common.txt + +:mod:`pygame.sndarray` +====================== + +.. module:: pygame.sndarray + :synopsis: pygame module for accessing sound sample data + +| :sl:`pygame module for accessing sound sample data` + +Functions to convert between NumPy arrays and Sound objects. This +module will only be functional when pygame can use the external NumPy +package. If NumPy can't be imported, ``surfarray`` becomes a ``MissingModule`` +object. + +Sound data is made of thousands of samples per second, and each sample is the +amplitude of the wave at a particular moment in time. For example, in 22-kHz +format, element number 5 of the array is the amplitude of the wave after +5/22000 seconds. + +The arrays are indexed by the ``X`` axis first, followed by the ``Y`` axis. +Each sample is an 8-bit or 16-bit integer, depending on the data format. A +stereo sound file has two values per sample, while a mono sound file only has +one. + +.. function:: array + + | :sl:`copy Sound samples into an array` + | :sg:`array(Sound) -> array` + + Creates a new array for the sound data and copies the samples. The array + will always be in the format returned from ``pygame.mixer.get_init()``. + + .. ## pygame.sndarray.array ## + +.. function:: samples + + | :sl:`reference Sound samples into an array` + | :sg:`samples(Sound) -> array` + + Creates a new array that directly references the samples in a Sound object. + Modifying the array will change the Sound. The array will always be in the + format returned from ``pygame.mixer.get_init()``. + + .. ## pygame.sndarray.samples ## + +.. function:: make_sound + + | :sl:`convert an array into a Sound object` + | :sg:`make_sound(array) -> Sound` + + Create a new playable Sound object from an array. The mixer module must be + initialized and the array format must be similar to the mixer audio format. + + .. ## pygame.sndarray.make_sound ## + +.. function:: use_arraytype + + | :sl:`Sets the array system to be used for sound arrays` + | :sg:`use_arraytype (arraytype) -> None` + + DEPRECATED: Uses the requested array type for the module functions. The + only supported arraytype is ``'numpy'``. Other values will raise ValueError. + Using this function will raise a ``DeprecationWarning``. + .. ## pygame.sndarray.use_arraytype ## + +.. function:: get_arraytype + + | :sl:`Gets the currently active array type.` + | :sg:`get_arraytype () -> str` + + DEPRECATED: Returns the currently active array type. This will be a value of the + ``get_arraytypes()`` tuple and indicates which type of array module is used + for the array creation. Using this function will raise a ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.sndarray.get_arraytype ## + +.. function:: get_arraytypes + + | :sl:`Gets the array system types currently supported.` + | :sg:`get_arraytypes () -> tuple` + + DEPRECATED: Checks, which array systems are available and returns them as a tuple of + strings. The values of the tuple can be used directly in the + :func:`pygame.sndarray.use_arraytype` () method. If no supported array + system could be found, None will be returned. Using this function will raise a + ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.sndarray.get_arraytypes ## + +.. ## pygame.sndarray ## diff --git a/docs/ref/sprite.rst b/docs/ref/sprite.rst new file mode 100644 index 0000000..82e8cbb --- /dev/null +++ b/docs/ref/sprite.rst @@ -0,0 +1,895 @@ +.. include:: common.txt + +:mod:`pygame.sprite` +==================== + +.. module:: pygame.sprite + :synopsis: pygame module with basic game object classes + +| :sl:`pygame module with basic game object classes` + +This module contains several simple classes to be used within games. There is +the main Sprite class and several Group classes that contain Sprites. The use +of these classes is entirely optional when using pygame. The classes are fairly +lightweight and only provide a starting place for the code that is common to +most games. + +The Sprite class is intended to be used as a base class for the different types +of objects in the game. There is also a base Group class that simply stores +sprites. A game could create new types of Group classes that operate on +specially customized Sprite instances they contain. + +The basic Group class can draw the Sprites it contains to a Surface. The +``Group.draw()`` method requires that each Sprite have a ``Surface.image`` +attribute and a ``Surface.rect``. The ``Group.clear()`` method requires these +same attributes, and can be used to erase all the Sprites with background. +There are also more advanced Groups: ``pygame.sprite.RenderUpdates()`` and +``pygame.sprite.OrderedUpdates()``. + +Lastly, this module contains several collision functions. These help find +sprites inside multiple groups that have intersecting bounding rectangles. To +find the collisions, the Sprites are required to have a ``Surface.rect`` +attribute assigned. + +The groups are designed for high efficiency in removing and adding Sprites to +them. They also allow cheap testing to see if a Sprite already exists in a +Group. A given Sprite can exist in any number of groups. A game could use some +groups to control object rendering, and a completely separate set of groups to +control interaction or player movement. Instead of adding type attributes or +bools to a derived Sprite class, consider keeping the Sprites inside organized +Groups. This will allow for easier lookup later in the game. + +Sprites and Groups manage their relationships with the ``add()`` and +``remove()`` methods. These methods can accept a single or multiple targets for +membership. The default initializers for these classes also takes a single or +list of targets for initial membership. It is safe to repeatedly add and remove +the same Sprite from a Group. + +While it is possible to design sprite and group classes that don't derive from +the Sprite and AbstractGroup classes below, it is strongly recommended that you +extend those when you add a Sprite or Group class. + +Sprites are not thread safe. So lock them yourself if using threads. + +.. class:: Sprite + + | :sl:`Simple base class for visible game objects.` + | :sg:`Sprite(*groups) -> Sprite` + + The base class for visible game objects. Derived classes will want to + override the ``Sprite.update()`` and assign a ``Sprite.image`` and + ``Sprite.rect`` attributes. The initializer can accept any number of Group + instances to be added to. + + When subclassing the Sprite, be sure to call the base initializer before + adding the Sprite to Groups. For example: + + .. code-block:: python + + class Block(pygame.sprite.Sprite): + + # Constructor. Pass in the color of the block, + # and its x and y position + def __init__(self, color, width, height): + # Call the parent class (Sprite) constructor + pygame.sprite.Sprite.__init__(self) + + # Create an image of the block, and fill it with a color. + # This could also be an image loaded from the disk. + self.image = pygame.Surface([width, height]) + self.image.fill(color) + + # Fetch the rectangle object that has the dimensions of the image + # Update the position of this object by setting the values of rect.x and rect.y + self.rect = self.image.get_rect() + + .. method:: update + + | :sl:`method to control sprite behavior` + | :sg:`update(*args, **kwargs) -> None` + + The default implementation of this method does nothing; it's just a + convenient "hook" that you can override. This method is called by + ``Group.update()`` with whatever arguments you give it. + + There is no need to use this method if not using the convenience method + by the same name in the Group class. + + .. ## Sprite.update ## + + .. method:: add + + | :sl:`add the sprite to groups` + | :sg:`add(*groups) -> None` + + Any number of Group instances can be passed as arguments. The Sprite will + be added to the Groups it is not already a member of. + + .. ## Sprite.add ## + + .. method:: remove + + | :sl:`remove the sprite from groups` + | :sg:`remove(*groups) -> None` + + Any number of Group instances can be passed as arguments. The Sprite will + be removed from the Groups it is currently a member of. + + .. ## Sprite.remove ## + + .. method:: kill + + | :sl:`remove the Sprite from all Groups` + | :sg:`kill() -> None` + + The Sprite is removed from all the Groups that contain it. This won't + change anything about the state of the Sprite. It is possible to continue + to use the Sprite after this method has been called, including adding it + to Groups. + + .. ## Sprite.kill ## + + .. method:: alive + + | :sl:`does the sprite belong to any groups` + | :sg:`alive() -> bool` + + Returns True when the Sprite belongs to one or more Groups. + + .. ## Sprite.alive ## + + .. method:: groups + + | :sl:`list of Groups that contain this Sprite` + | :sg:`groups() -> group_list` + + Return a list of all the Groups that contain this Sprite. + + .. ## Sprite.groups ## + + .. ## pygame.sprite.Sprite ## + +.. class:: WeakSprite + + | :sl:`A subclass of Sprite that references its Groups weakly. This means that any group this belongs to that is not referenced anywhere else is garbage collected automatically.` + | :sg:`WeakSprite(*groups) -> WeakSprite` + +.. class:: DirtySprite + + | :sl:`A subclass of Sprite with more attributes and features.` + | :sg:`DirtySprite(*groups) -> DirtySprite` + + Extra DirtySprite attributes with their default values: + + dirty = 1 + + :: + + if set to 1, it is repainted and then set to 0 again + if set to 2 then it is always dirty ( repainted each frame, + flag is not reset) + 0 means that it is not dirty and therefore not repainted again + + blendmode = 0 + + :: + + its the special_flags argument of blit, blendmodes + + source_rect = None + + :: + + source rect to use, remember that it is relative to + topleft (0,0) of self.image + + visible = 1 + + :: + + normally 1, if set to 0 it will not be repainted + (you must set it dirty too to be erased from screen) + + layer = 0 + + :: + + (READONLY value, it is read when adding it to the + LayeredDirty, for details see doc of LayeredDirty) + + .. ## ## + + .. ## pygame.sprite.DirtySprite ## + +.. class:: Group + + | :sl:`A container class to hold and manage multiple Sprite objects.` + | :sg:`Group(*sprites) -> Group` + + A simple container for Sprite objects. This class can be inherited to create + containers with more specific behaviors. The constructor takes any number of + Sprite arguments to add to the Group. The group supports the following + standard Python operations: + + :: + + in test if a Sprite is contained + len the number of Sprites contained + bool test if any Sprites are contained + iter iterate through all the Sprites + + The Sprites in the Group are ordered only on python 3.6 and higher. + Below python 3.6 drawing and iterating over the Sprites is in no particular order. + + .. method:: sprites + + | :sl:`list of the Sprites this Group contains` + | :sg:`sprites() -> sprite_list` + + Return a list of all the Sprites this group contains. You can also get an + iterator from the group, but you cannot iterate over a Group while + modifying it. + + .. ## Group.sprites ## + + .. method:: copy + + | :sl:`duplicate the Group` + | :sg:`copy() -> Group` + + Creates a new Group with all the same Sprites as the original. If you + have subclassed Group, the new object will have the same (sub-)class as + the original. This only works if the derived class's constructor takes + the same arguments as the Group class's. + + .. ## Group.copy ## + + .. method:: add + + | :sl:`add Sprites to this Group` + | :sg:`add(*sprites) -> None` + + Add any number of Sprites to this Group. This will only add Sprites that + are not already members of the Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.add ## + + .. method:: remove + + | :sl:`remove Sprites from the Group` + | :sg:`remove(*sprites) -> None` + + Remove any number of Sprites from the Group. This will only remove + Sprites that are already members of the Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.remove ## + + .. method:: has + + | :sl:`test if a Group contains Sprites` + | :sg:`has(*sprites) -> bool` + + Return True if the Group contains all of the given sprites. This is + similar to using the "in" operator on the Group ("if sprite in group: + ..."), which tests if a single Sprite belongs to a Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.has ## + + .. method:: update + + | :sl:`call the update method on contained Sprites` + | :sg:`update(*args, **kwargs) -> None` + + Calls the ``update()`` method on all Sprites in the Group. The base + Sprite class has an update method that takes any number of arguments and + does nothing. The arguments passed to ``Group.update()`` will be passed + to each Sprite. + + There is no way to get the return value from the ``Sprite.update()`` + methods. + + .. ## Group.update ## + + .. method:: draw + + | :sl:`blit the Sprite images` + | :sg:`draw(Surface, bgsurf=None, special_flags=0) -> List[Rect]` + + Draws the contained Sprites to the Surface argument. This uses the + ``Sprite.image`` attribute for the source surface, and ``Sprite.rect`` + for the position. ``special_flags`` is passed to ``Surface.blit()``. + ``bgsurf`` is unused in this method but ``LayeredDirty.draw()`` uses + it. + + The Group does not keep sprites in any order, so the draw order is + arbitrary. + + .. ## Group.draw ## + + .. method:: clear + + | :sl:`draw a background over the Sprites` + | :sg:`clear(Surface_dest, background) -> None` + + Erases the Sprites used in the last ``Group.draw()`` call. The + destination Surface is cleared by filling the drawn Sprite positions with + the background. + + The background is usually a Surface image the same dimensions as the + destination Surface. However, it can also be a callback function that + takes two arguments; the destination Surface and an area to clear. The + background callback function will be called several times each clear. + + Here is an example callback that will clear the Sprites with solid red: + + :: + + def clear_callback(surf, rect): + color = 255, 0, 0 + surf.fill(color, rect) + + .. ## Group.clear ## + + .. method:: empty + + | :sl:`remove all Sprites` + | :sg:`empty() -> None` + + Removes all Sprites from this Group. + + .. ## Group.empty ## + + .. ## pygame.sprite.Group ## + +.. class:: WeakDirtySprite + + | :sl:`A subclass of WeakSprite and DirtySprite that combines the benefits of both classes.` + | :sg:`WeakDirtySprite(*groups) -> WeakDirtySprite` + +.. class:: RenderPlain + + | :sl:`Same as pygame.sprite.Group` + + This class is an alias to ``pygame.sprite.Group()``. It has no additional functionality. + + .. ## pygame.sprite.RenderClear ## + +.. class:: RenderClear + + | :sl:`Same as pygame.sprite.Group` + + This class is an alias to ``pygame.sprite.Group()``. It has no additional functionality. + + .. ## pygame.sprite.RenderClear ## + +.. class:: RenderUpdates + + | :sl:`Group sub-class that tracks dirty updates.` + | :sg:`RenderUpdates(*sprites) -> RenderUpdates` + + This class is derived from ``pygame.sprite.Group()``. It has an extended + ``draw()`` method that tracks the changed areas of the screen. + + .. method:: draw + + | :sl:`blit the Sprite images and track changed areas` + | :sg:`draw(surface, bgsurf=None, special_flags=0) -> Rect_list` + + Draws all the Sprites to the surface, the same as ``Group.draw()``. This + method also returns a list of Rectangular areas on the screen that have + been changed. The returned changes include areas of the screen that have + been affected by previous ``Group.clear()`` calls. ``special_flags`` is + passed to ``Surface.blit()``. + + The returned Rect list should be passed to ``pygame.display.update()``. + This will help performance on software driven display modes. This type of + updating is usually only helpful on destinations with non-animating + backgrounds. + + .. ## RenderUpdates.draw ## + + .. ## pygame.sprite.RenderUpdates ## + +.. function:: OrderedUpdates + + | :sl:`RenderUpdates sub-class that draws Sprites in order of addition.` + | :sg:`OrderedUpdates(*sprites) -> OrderedUpdates` + + This class derives from ``pygame.sprite.RenderUpdates()``. It maintains the + order in which the Sprites were added to the Group for rendering. This makes + adding and removing Sprites from the Group a little slower than regular + Groups. + + .. ## pygame.sprite.OrderedUpdates ## + +.. class:: LayeredUpdates + + | :sl:`LayeredUpdates is a sprite group that handles layers and draws like OrderedUpdates.` + | :sg:`LayeredUpdates(*sprites, **kwargs) -> LayeredUpdates` + + This group is fully compatible with :class:`pygame.sprite.Sprite`. + + You can set the default layer through kwargs using 'default_layer' and an + integer for the layer. The default layer is 0. + + If the sprite you add has an attribute _layer then that layer will be used. + If the \**kwarg contains 'layer' then the sprites passed will be added to + that layer (overriding the ``sprite.layer`` attribute). If neither sprite + has attribute layer nor \**kwarg then the default layer is used to add the + sprites. + + .. versionadded:: 1.8 + + .. method:: add + + | :sl:`add a sprite or sequence of sprites to a group` + | :sg:`add(*sprites, **kwargs) -> None` + + If the ``sprite(s)`` have an attribute layer then that is used for the + layer. If \**kwargs contains 'layer' then the ``sprite(s)`` will be added + to that argument (overriding the sprite layer attribute). If neither is + passed then the ``sprite(s)`` will be added to the default layer. + + .. ## LayeredUpdates.add ## + + .. method:: sprites + + | :sl:`returns a ordered list of sprites (first back, last top).` + | :sg:`sprites() -> sprites` + + .. ## LayeredUpdates.sprites ## + + .. method:: draw + + | :sl:`draw all sprites in the right order onto the passed surface.` + | :sg:`draw(surface, bgsurf=None, special_flags=0) -> Rect_list` + + .. ## LayeredUpdates.draw ## + + .. method:: get_sprites_at + + | :sl:`returns a list with all sprites at that position.` + | :sg:`get_sprites_at(pos) -> colliding_sprites` + + Bottom sprites first, top last. + + .. ## LayeredUpdates.get_sprites_at ## + + .. method:: get_sprite + + | :sl:`returns the sprite at the index idx from the groups sprites` + | :sg:`get_sprite(idx) -> sprite` + + Raises IndexOutOfBounds if the idx is not within range. + + .. ## LayeredUpdates.get_sprite ## + + .. method:: remove_sprites_of_layer + + | :sl:`removes all sprites from a layer and returns them as a list.` + | :sg:`remove_sprites_of_layer(layer_nr) -> sprites` + + .. ## LayeredUpdates.remove_sprites_of_layer ## + + .. method:: layers + + | :sl:`returns a list of layers defined (unique), sorted from bottom up.` + | :sg:`layers() -> layers` + + .. ## LayeredUpdates.layers ## + + .. method:: change_layer + + | :sl:`changes the layer of the sprite` + | :sg:`change_layer(sprite, new_layer) -> None` + + sprite must have been added to the renderer. It is not checked. + + .. ## LayeredUpdates.change_layer ## + + .. method:: get_layer_of_sprite + + | :sl:`returns the layer that sprite is currently in.` + | :sg:`get_layer_of_sprite(sprite) -> layer` + + If the sprite is not found then it will return the default layer. + + .. ## LayeredUpdates.get_layer_of_sprite ## + + .. method:: get_top_layer + + | :sl:`returns the top layer` + | :sg:`get_top_layer() -> layer` + + .. ## LayeredUpdates.get_top_layer ## + + .. method:: get_bottom_layer + + | :sl:`returns the bottom layer` + | :sg:`get_bottom_layer() -> layer` + + .. ## LayeredUpdates.get_bottom_layer ## + + .. method:: move_to_front + + | :sl:`brings the sprite to front layer` + | :sg:`move_to_front(sprite) -> None` + + Brings the sprite to front, changing sprite layer to topmost layer (added + at the end of that layer). + + .. ## LayeredUpdates.move_to_front ## + + .. method:: move_to_back + + | :sl:`moves the sprite to the bottom layer` + | :sg:`move_to_back(sprite) -> None` + + Moves the sprite to the bottom layer, moving it behind all other layers + and adding one additional layer. + + .. ## LayeredUpdates.move_to_back ## + + .. method:: get_top_sprite + + | :sl:`returns the topmost sprite` + | :sg:`get_top_sprite() -> Sprite` + + .. ## LayeredUpdates.get_top_sprite ## + + .. method:: get_sprites_from_layer + + | :sl:`returns all sprites from a layer, ordered by how they where added` + | :sg:`get_sprites_from_layer(layer) -> sprites` + + Returns all sprites from a layer, ordered by how they where added. It + uses linear search and the sprites are not removed from layer. + + .. ## LayeredUpdates.get_sprites_from_layer ## + + .. method:: switch_layer + + | :sl:`switches the sprites from layer1 to layer2` + | :sg:`switch_layer(layer1_nr, layer2_nr) -> None` + + The layers number must exist, it is not checked. + + .. ## LayeredUpdates.switch_layer ## + + .. ## pygame.sprite.LayeredUpdates ## + +.. class:: LayeredDirty + + | :sl:`LayeredDirty group is for DirtySprite objects. Subclasses LayeredUpdates.` + | :sg:`LayeredDirty(*sprites, **kwargs) -> LayeredDirty` + + This group requires :class:`pygame.sprite.DirtySprite` or any sprite that + has the following attributes: + + :: + + image, rect, dirty, visible, blendmode (see doc of DirtySprite). + + It uses the dirty flag technique and is therefore faster than the + :class:`pygame.sprite.RenderUpdates` if you have many static sprites. It + also switches automatically between dirty rect update and full screen + drawing, so you do not have to worry what would be faster. + + Same as for the :class:`pygame.sprite.Group`. You can specify some + additional attributes through kwargs: + + :: + + _use_update: True/False default is False + _default_layer: default layer where sprites without a layer are added. + _time_threshold: threshold time for switching between dirty rect mode + and fullscreen mode, defaults to 1000./80 == 1000./fps + + .. versionadded:: 1.8 + + .. method:: draw + + | :sl:`draw all sprites in the right order onto the passed surface.` + | :sg:`draw(surface, bgsurf=None, special_flags=None) -> Rect_list` + + You can pass the background too. If a background is already set, then the + bgsurf argument has no effect. If present, the ``special_flags`` argument is + always passed to ``Surface.blit()``, overriding ``DirtySprite.blendmode``. + If ``special_flags`` is not present, ``DirtySprite.blendmode`` is passed + to the ``Surface.blit()`` instead. + + .. ## LayeredDirty.draw ## + + .. method:: clear + + | :sl:`used to set background` + | :sg:`clear(surface, bgd) -> None` + + .. ## LayeredDirty.clear ## + + .. method:: repaint_rect + + | :sl:`repaints the given area` + | :sg:`repaint_rect(screen_rect) -> None` + + screen_rect is in screen coordinates. + + .. ## LayeredDirty.repaint_rect ## + + .. method:: set_clip + + | :sl:`clip the area where to draw. Just pass None (default) to reset the clip` + | :sg:`set_clip(screen_rect=None) -> None` + + .. ## LayeredDirty.set_clip ## + + .. method:: get_clip + + | :sl:`clip the area where to draw. Just pass None (default) to reset the clip` + | :sg:`get_clip() -> Rect` + + .. ## LayeredDirty.get_clip ## + + .. method:: change_layer + + | :sl:`changes the layer of the sprite` + | :sg:`change_layer(sprite, new_layer) -> None` + + sprite must have been added to the renderer. It is not checked. + + .. ## LayeredDirty.change_layer ## + + .. method:: set_timing_treshold + + | :sl:`sets the threshold in milliseconds` + | :sg:`set_timing_treshold(time_ms) -> None` + + DEPRECATED: Use set_timing_threshold() instead. + + .. deprecated:: 2.1.1 + + .. ## LayeredDirty.set_timing_treshold ## + + .. method:: set_timing_threshold + + | :sl:`sets the threshold in milliseconds` + | :sg:`set_timing_threshold(time_ms) -> None` + + Defaults to 1000.0 / 80.0. This means that the screen will be painted + using the flip method rather than the update method if the update + method is taking so long to update the screen that the frame rate falls + below 80 frames per second. + + .. versionadded:: 2.1.1 + + :raises TypeError: if ``time_ms`` is not int or float + + .. ## LayeredDirty.set_timing_threshold ## + + .. ## pygame.sprite.LayeredDirty ## + +.. function:: GroupSingle + + | :sl:`Group container that holds a single sprite.` + | :sg:`GroupSingle(sprite=None) -> GroupSingle` + + The GroupSingle container only holds a single Sprite. When a new Sprite is + added, the old one is removed. + + There is a special property, ``GroupSingle.sprite``, that accesses the + Sprite that this Group contains. It can be None when the Group is empty. The + property can also be assigned to add a Sprite into the GroupSingle + container. + + .. ## pygame.sprite.GroupSingle ## + +.. function:: spritecollide + + | :sl:`Find sprites in a group that intersect another sprite.` + | :sg:`spritecollide(sprite, group, dokill, collided = None) -> Sprite_list` + + Return a list containing all Sprites in a Group that intersect with another + Sprite. Intersection is determined by comparing the ``Sprite.rect`` + attribute of each Sprite. + + The dokill argument is a bool. If set to True, all Sprites that collide will + be removed from the Group. + + The collided argument is a callback function used to calculate if two + sprites are colliding. it should take two sprites as values, and return a + bool value indicating if they are colliding. If collided is not passed, all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + collided callables: + + :: + + collide_rect, collide_rect_ratio, collide_circle, + collide_circle_ratio, collide_mask + + Example: + + .. code-block:: python + + # See if the Sprite block has collided with anything in the Group block_list + # The True flag will remove the sprite in block_list + blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True) + + # Check the list of colliding sprites, and add one to the score for each one + for block in blocks_hit_list: + score +=1 + + .. ## pygame.sprite.spritecollide ## + +.. function:: collide_rect + + | :sl:`Collision detection between two sprites, using rects.` + | :sg:`collide_rect(left, right) -> bool` + + Tests for collision between two sprites. Uses the pygame rect colliderect + function to calculate the collision. Intended to be passed as a collided + callback function to the \*collide functions. Sprites must have a "rect" + attributes. + + .. versionadded:: 1.8 + + .. ## pygame.sprite.collide_rect ## + +.. function:: collide_rect_ratio + + | :sl:`Collision detection between two sprites, using rects scaled to a ratio.` + | :sg:`collide_rect_ratio(ratio) -> collided_callable` + + A callable class that checks for collisions between two sprites, using a + scaled version of the sprites rects. + + Is created with a ratio, the instance is then intended to be passed as a + collided callback function to the \*collide functions. + + A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as + big, and 0.5 is half the size. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_rect_ratio ## + +.. function:: collide_circle + + | :sl:`Collision detection between two sprites, using circles.` + | :sg:`collide_circle(left, right) -> bool` + + Tests for collision between two sprites, by testing to see if two circles + centered on the sprites overlap. If the sprites have a "radius" attribute, + that is used to create the circle, otherwise a circle is created that is big + enough to completely enclose the sprites rect as given by the "rect" + attribute. Intended to be passed as a collided callback function to the + \*collide functions. Sprites must have a "rect" and an optional "radius" + attribute. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_circle ## + +.. function:: collide_circle_ratio + + | :sl:`Collision detection between two sprites, using circles scaled to a ratio.` + | :sg:`collide_circle_ratio(ratio) -> collided_callable` + + A callable class that checks for collisions between two sprites, using a + scaled version of the sprites radius. + + Is created with a floating point ratio, the instance is then intended to be + passed as a collided callback function to the \*collide functions. + + A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as + big, and 0.5 is half the size. + + The created callable tests for collision between two sprites, by testing to + see if two circles centered on the sprites overlap, after scaling the + circles radius by the stored ratio. If the sprites have a "radius" + attribute, that is used to create the circle, otherwise a circle is created + that is big enough to completely enclose the sprites rect as given by the + "rect" attribute. Intended to be passed as a collided callback function to + the \*collide functions. Sprites must have a "rect" and an optional "radius" + attribute. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_circle_ratio ## + +.. function:: collide_mask + + | :sl:`Collision detection between two sprites, using masks.` + | :sg:`collide_mask(sprite1, sprite2) -> (int, int)` + | :sg:`collide_mask(sprite1, sprite2) -> None` + + Tests for collision between two sprites, by testing if their bitmasks + overlap (uses :func:`pygame.mask.Mask.overlap`). If the sprites have a + ``mask`` attribute, it is used as the mask, otherwise a mask is created from + the sprite's ``image`` (uses :func:`pygame.mask.from_surface`). Sprites must + have a ``rect`` attribute; the ``mask`` attribute is optional. + + The first point of collision between the masks is returned. The collision + point is offset from ``sprite1``'s mask's topleft corner (which is always + (0, 0)). The collision point is a position within the mask and is not + related to the actual screen position of ``sprite1``. + + This function is intended to be passed as a ``collided`` callback function + to the group collide functions (see :meth:`spritecollide`, + :meth:`groupcollide`, :meth:`spritecollideany`). + + .. note:: + To increase performance, create and set a ``mask`` attribute for all + sprites that will use this function to check for collisions. Otherwise, + each time this function is called it will create new masks. + + .. note:: + A new mask needs to be recreated each time a sprite's image is changed + (e.g. if a new image is used or the existing image is rotated). + + :: + + # Example of mask creation for a sprite. + sprite.mask = pygame.mask.from_surface(sprite.image) + + :returns: first point of collision between the masks or ``None`` if no + collision + :rtype: tuple(int, int) or NoneType + + .. versionadded:: 1.8.0 + + .. ## pygame.sprite.collide_mask ## + +.. function:: groupcollide + + | :sl:`Find all sprites that collide between two groups.` + | :sg:`groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict` + + This will find collisions between all the Sprites in two groups. + Collision is determined by comparing the ``Sprite.rect`` attribute of + each Sprite or by using the collided function if it is not None. + + Every Sprite inside group1 is added to the return dictionary. The value for + each item is the list of Sprites in group2 that intersect. + + If either dokill argument is True, the colliding Sprites will be removed + from their respective Group. + + The collided argument is a callback function used to calculate if two sprites are + colliding. It should take two sprites as values and return a bool value + indicating if they are colliding. If collided is not passed, then all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + .. ## pygame.sprite.groupcollide ## + +.. function:: spritecollideany + + | :sl:`Simple test if a sprite intersects anything in a group.` + | :sg:`spritecollideany(sprite, group, collided = None) -> Sprite` Collision with the returned sprite. + | :sg:`spritecollideany(sprite, group, collided = None) -> None` No collision + + If the sprite collides with any single sprite in the group, a single + sprite from the group is returned. On no collision None is returned. + + If you don't need all the features of the ``pygame.sprite.spritecollide()`` function, this + function will be a bit quicker. + + The collided argument is a callback function used to calculate if two sprites are + colliding. It should take two sprites as values and return a bool value + indicating if they are colliding. If collided is not passed, then all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + .. ## pygame.sprite.spritecollideany ## + +.. ## ## + +.. ## pygame.sprite ## diff --git a/docs/ref/surface.rst b/docs/ref/surface.rst new file mode 100644 index 0000000..82466fc --- /dev/null +++ b/docs/ref/surface.rst @@ -0,0 +1,949 @@ +.. include:: common.txt + +:mod:`pygame.Surface` +===================== + +.. currentmodule:: pygame + +.. class:: Surface + + | :sl:`pygame object for representing images` + | :sg:`Surface((width, height), flags=0, depth=0, masks=None) -> Surface` + | :sg:`Surface((width, height), flags=0, Surface) -> Surface` + + A pygame Surface is used to represent any image. The Surface has a fixed + resolution and pixel format. Surfaces with 8-bit pixels use a color palette + to map to 24-bit color. + + Call :meth:`pygame.Surface()` to create a new image object. The Surface will + be cleared to all black. The only required arguments are the sizes. With no + additional arguments, the Surface will be created in a format that best + matches the display Surface. + + The pixel format can be controlled by passing the bit depth or an existing + Surface. The flags argument is a bitmask of additional features for the + surface. You can pass any combination of these flags: + + :: + + HWSURFACE (obsolete in pygame 2) creates the image in video memory + SRCALPHA the pixel format will include a per-pixel alpha + + Both flags are only a request, and may not be possible for all displays and + formats. + + Advance users can combine a set of bitmasks with a depth value. The masks + are a set of 4 integers representing which bits in a pixel will represent + each color. Normal Surfaces should not require the masks argument. + + Surfaces can have many extra attributes like alpha planes, colorkeys, source + rectangle clipping. These functions mainly effect how the Surface is blitted + to other Surfaces. The blit routines will attempt to use hardware + acceleration when possible, otherwise they will use highly optimized + software blitting methods. + + There are three types of transparency supported in pygame: colorkeys, + surface alphas, and pixel alphas. Surface alphas can be mixed with + colorkeys, but an image with per pixel alphas cannot use the other modes. + Colorkey transparency makes a single color value transparent. Any pixels + matching the colorkey will not be drawn. The surface alpha value is a single + value that changes the transparency for the entire image. A surface alpha of + 255 is opaque, and a value of 0 is completely transparent. + + Per pixel alphas are different because they store a transparency value for + every pixel. This allows for the most precise transparency effects, but it + also the slowest. Per pixel alphas cannot be mixed with surface alpha and + colorkeys. + + There is support for pixel access for the Surfaces. Pixel access on hardware + surfaces is slow and not recommended. Pixels can be accessed using the + :meth:`get_at()` and :meth:`set_at()` functions. These methods are fine for + simple access, but will be considerably slow when doing of pixel work with + them. If you plan on doing a lot of pixel level work, it is recommended to + use a :class:`pygame.PixelArray`, which gives an array like view of the + surface. For involved mathematical manipulations try the + :mod:`pygame.surfarray` module (It's quite quick, but requires NumPy.) + + Any functions that directly access a surface's pixel data will need that + surface to be lock()'ed. These functions can :meth:`lock()` and + :meth:`unlock()` the surfaces themselves without assistance. But, if a + function will be called many times, there will be a lot of overhead for + multiple locking and unlocking of the surface. It is best to lock the + surface manually before making the function call many times, and then + unlocking when you are finished. All functions that need a locked surface + will say so in their docs. Remember to leave the Surface locked only while + necessary. + + Surface pixels are stored internally as a single number that has all the + colors encoded into it. Use the :meth:`map_rgb()` and + :meth:`unmap_rgb()` to convert between individual red, green, and blue + values into a packed integer for that Surface. + + Surfaces can also reference sections of other Surfaces. These are created + with the :meth:`subsurface()` method. Any change to either Surface will + effect the other. + + Each Surface contains a clipping area. By default the clip area covers the + entire Surface. If it is changed, all drawing operations will only effect + the smaller area. + + .. method:: blit + + | :sl:`draw one image onto another` + | :sg:`blit(source, dest, area=None, special_flags=0) -> Rect` + + Draws a source Surface onto this Surface. The draw can be positioned with + the dest argument. The dest argument can either be a pair of coordinates representing the position of + the upper left corner of the blit or a Rect, where the upper left corner of the rectangle will be used as the + position for the blit. The size of the destination rectangle does not + effect the blit. + + An optional area rectangle can be passed as well. This represents a + smaller portion of the source Surface to draw. + + .. versionadded:: 1.8 + Optional ``special_flags``: ``BLEND_ADD``, ``BLEND_SUB``, + ``BLEND_MULT``, ``BLEND_MIN``, ``BLEND_MAX``. + + .. versionadded:: 1.8.1 + Optional ``special_flags``: ``BLEND_RGBA_ADD``, ``BLEND_RGBA_SUB``, + ``BLEND_RGBA_MULT``, ``BLEND_RGBA_MIN``, ``BLEND_RGBA_MAX`` + ``BLEND_RGB_ADD``, ``BLEND_RGB_SUB``, ``BLEND_RGB_MULT``, + ``BLEND_RGB_MIN``, ``BLEND_RGB_MAX``. + + .. versionadded:: 1.9.2 + Optional ``special_flags``: ``BLEND_PREMULTIPLIED`` + + .. versionadded:: 2.0.0 + Optional ``special_flags``: ``BLEND_ALPHA_SDL2`` - Uses the SDL2 blitter for alpha blending, + this gives different results than the default blitter, which is modelled after SDL1, due to + different approximations used for the alpha blending formula. The SDL2 blitter also supports + RLE on alpha blended surfaces which the pygame one does not. + + The return rectangle is the area of the affected pixels, excluding any + pixels outside the destination Surface, or outside the clipping area. + + Pixel alphas will be ignored when blitting to an 8 bit Surface. + + For a surface with colorkey or blanket alpha, a blit to self may give + slightly different colors than a non self-blit. + + .. ## Surface.blit ## + + .. method:: blits + + | :sl:`draw many images onto another` + | :sg:`blits(blit_sequence=((source, dest), ...), doreturn=1) -> [Rect, ...] or None` + | :sg:`blits(((source, dest, area), ...)) -> [Rect, ...]` + | :sg:`blits(((source, dest, area, special_flags), ...)) -> [Rect, ...]` + + Draws many surfaces onto this Surface. It takes a sequence as input, + with each of the elements corresponding to the ones of :meth:`blit()`. + It needs at minimum a sequence of (source, dest). + + :param blit_sequence: a sequence of surfaces and arguments to blit them, + they correspond to the :meth:`blit()` arguments + :param doreturn: if ``True``, return a list of rects of the areas changed, + otherwise return ``None`` + + :returns: a list of rects of the areas changed if ``doreturn`` is + ``True``, otherwise ``None`` + :rtype: list or None + + New in pygame 1.9.4. + + .. ## Surface.blits ## + + + .. method:: convert + + | :sl:`change the pixel format of an image` + | :sg:`convert(Surface=None) -> Surface` + | :sg:`convert(depth, flags=0) -> Surface` + | :sg:`convert(masks, flags=0) -> Surface` + + Creates a new copy of the Surface with the pixel format changed. The new + pixel format can be determined from another existing Surface. Otherwise + depth, flags, and masks arguments can be used, similar to the + :meth:`pygame.Surface()` call. + + If no arguments are passed the new Surface will have the same pixel + format as the display Surface. This is always the fastest format for + blitting. It is a good idea to convert all Surfaces before they are + blitted many times. + + The converted Surface will have no pixel alphas. They will be stripped if + the original had them. See :meth:`convert_alpha()` for preserving or + creating per-pixel alphas. + + The new copy will have the same class as the copied surface. This lets + as Surface subclass inherit this method without the need to override, + unless subclass specific instance attributes also need copying. + + .. ## Surface.convert ## + + .. method:: convert_alpha + + | :sl:`change the pixel format of an image including per pixel alphas` + | :sg:`convert_alpha(Surface) -> Surface` + | :sg:`convert_alpha() -> Surface` + + Creates a new copy of the surface with the desired pixel format. The new + surface will be in a format suited for quick blitting to the given format + with per pixel alpha. If no surface is given, the new surface will be + optimized for blitting to the current display. + + Unlike the :meth:`convert()` method, the pixel format for the new + image will not be exactly the same as the requested source, but it will + be optimized for fast alpha blitting to the destination. + + As with :meth:`convert()` the returned surface has the same class as + the converted surface. + + .. ## Surface.convert_alpha ## + + .. method:: copy + + | :sl:`create a new copy of a Surface` + | :sg:`copy() -> Surface` + + Makes a duplicate copy of a Surface. The new surface will have the same + pixel formats, color palettes, transparency settings, and class as the + original. If a Surface subclass also needs to copy any instance specific + attributes then it should override ``copy()``. + + .. ## Surface.copy ## + + .. method:: fill + + | :sl:`fill Surface with a solid color` + | :sg:`fill(color, rect=None, special_flags=0) -> Rect` + + Fill the Surface with a solid color. If no rect argument is given the + entire Surface will be filled. The rect argument will limit the fill to a + specific area. The fill will also be contained by the Surface clip area. + + The color argument can be either a ``RGB`` sequence, a ``RGBA`` sequence + or a mapped color index. If using ``RGBA``, the Alpha (A part of + ``RGBA``) is ignored unless the surface uses per pixel alpha (Surface has + the ``SRCALPHA`` flag). + + .. versionadded:: 1.8 + Optional ``special_flags``: ``BLEND_ADD``, ``BLEND_SUB``, + ``BLEND_MULT``, ``BLEND_MIN``, ``BLEND_MAX``. + + .. versionadded:: 1.8.1 + Optional ``special_flags``: ``BLEND_RGBA_ADD``, ``BLEND_RGBA_SUB``, + ``BLEND_RGBA_MULT``, ``BLEND_RGBA_MIN``, ``BLEND_RGBA_MAX`` + ``BLEND_RGB_ADD``, ``BLEND_RGB_SUB``, ``BLEND_RGB_MULT``, + ``BLEND_RGB_MIN``, ``BLEND_RGB_MAX``. + + This will return the affected Surface area. + + .. ## Surface.fill ## + + .. method:: scroll + + | :sl:`Shift the surface image in place` + | :sg:`scroll(dx=0, dy=0) -> None` + + Move the image by dx pixels right and dy pixels down. dx and dy may be + negative for left and up scrolls respectively. Areas of the surface that + are not overwritten retain their original pixel values. Scrolling is + contained by the Surface clip area. It is safe to have dx and dy values + that exceed the surface size. + + .. versionadded:: 1.9 + + .. ## Surface.scroll ## + + .. method:: set_colorkey + + | :sl:`Set the transparent colorkey` + | :sg:`set_colorkey(Color, flags=0) -> None` + | :sg:`set_colorkey(None) -> None` + + Set the current color key for the Surface. When blitting this Surface + onto a destination, any pixels that have the same color as the colorkey + will be transparent. The color can be an ``RGB`` color or a mapped color + integer. If ``None`` is passed, the colorkey will be unset. + + The colorkey will be ignored if the Surface is formatted to use per pixel + alpha values. The colorkey can be mixed with the full Surface alpha + value. + + The optional flags argument can be set to ``pygame.RLEACCEL`` to provide + better performance on non accelerated displays. An ``RLEACCEL`` Surface + will be slower to modify, but quicker to blit as a source. + + .. ## Surface.set_colorkey ## + + .. method:: get_colorkey + + | :sl:`Get the current transparent colorkey` + | :sg:`get_colorkey() -> RGB or None` + + Return the current colorkey value for the Surface. If the colorkey is not + set then ``None`` is returned. + + .. ## Surface.get_colorkey ## + + .. method:: set_alpha + + | :sl:`set the alpha value for the full Surface image` + | :sg:`set_alpha(value, flags=0) -> None` + | :sg:`set_alpha(None) -> None` + + Set the current alpha value for the Surface. When blitting this Surface + onto a destination, the pixels will be drawn slightly transparent. The + alpha value is an integer from 0 to 255, 0 is fully transparent and 255 + is fully opaque. If ``None`` is passed for the alpha value, then alpha + blending will be disabled, including per-pixel alpha. + + This value is different than the per pixel Surface alpha. For a surface + with per pixel alpha, blanket alpha is ignored and ``None`` is returned. + + .. versionchanged:: 2.0 per-surface alpha can be combined with per-pixel + alpha. + + The optional flags argument can be set to ``pygame.RLEACCEL`` to provide + better performance on non accelerated displays. An ``RLEACCEL`` Surface + will be slower to modify, but quicker to blit as a source. + + .. ## Surface.set_alpha ## + + .. method:: get_alpha + + | :sl:`get the current Surface transparency value` + | :sg:`get_alpha() -> int_value` + + Return the current alpha value for the Surface. + + .. ## Surface.get_alpha ## + + .. method:: lock + + | :sl:`lock the Surface memory for pixel access` + | :sg:`lock() -> None` + + Lock the pixel data of a Surface for access. On accelerated Surfaces, the + pixel data may be stored in volatile video memory or nonlinear compressed + forms. When a Surface is locked the pixel memory becomes available to + access by regular software. Code that reads or writes pixel values will + need the Surface to be locked. + + Surfaces should not remain locked for more than necessary. A locked + Surface can often not be displayed or managed by pygame. + + Not all Surfaces require locking. The :meth:`mustlock()` method can + determine if it is actually required. There is no performance penalty for + locking and unlocking a Surface that does not need it. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + It is safe to nest locking and unlocking calls. The surface will only be + unlocked after the final lock is released. + + .. ## Surface.lock ## + + .. method:: unlock + + | :sl:`unlock the Surface memory from pixel access` + | :sg:`unlock() -> None` + + Unlock the Surface pixel data after it has been locked. The unlocked + Surface can once again be drawn and managed by pygame. See the + :meth:`lock()` documentation for more details. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + It is safe to nest locking and unlocking calls. The surface will only be + unlocked after the final lock is released. + + .. ## Surface.unlock ## + + .. method:: mustlock + + | :sl:`test if the Surface requires locking` + | :sg:`mustlock() -> bool` + + Returns ``True`` if the Surface is required to be locked to access pixel + data. Usually pure software Surfaces do not require locking. This method + is rarely needed, since it is safe and quickest to just lock all Surfaces + as needed. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + .. ## Surface.mustlock ## + + .. method:: get_locked + + | :sl:`test if the Surface is current locked` + | :sg:`get_locked() -> bool` + + Returns ``True`` when the Surface is locked. It doesn't matter how many + times the Surface is locked. + + .. ## Surface.get_locked ## + + .. method:: get_locks + + | :sl:`Gets the locks for the Surface` + | :sg:`get_locks() -> tuple` + + Returns the currently existing locks for the Surface. + + .. ## Surface.get_locks ## + + .. method:: get_at + + | :sl:`get the color value at a single pixel` + | :sg:`get_at((x, y)) -> Color` + + Return a copy of the ``RGBA`` Color value at the given pixel. If the + Surface has no per pixel alpha, then the alpha value will always be 255 + (opaque). If the pixel position is outside the area of the Surface an + ``IndexError`` exception will be raised. + + Getting and setting pixels one at a time is generally too slow to be used + in a game or realtime situation. It is better to use methods which + operate on many pixels at a time like with the blit, fill and draw + methods - or by using :mod:`pygame.surfarray`/:mod:`pygame.PixelArray`. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.9 + Returning a Color instead of tuple. Use ``tuple(surf.get_at((x,y)))`` + if you want a tuple, and not a Color. This should only matter if + you want to use the color as a key in a dict. + + .. ## Surface.get_at ## + + .. method:: set_at + + | :sl:`set the color value for a single pixel` + | :sg:`set_at((x, y), Color) -> None` + + Set the ``RGBA`` or mapped integer color value for a single pixel. If the + Surface does not have per pixel alphas, the alpha value is ignored. + Setting pixels outside the Surface area or outside the Surface clipping + will have no effect. + + Getting and setting pixels one at a time is generally too slow to be used + in a game or realtime situation. + + This function will temporarily lock and unlock the Surface as needed. + + .. note:: If the surface is palettized, the pixel color will be set to the + most similar color in the palette. + + .. ## Surface.set_at ## + + .. method:: get_at_mapped + + | :sl:`get the mapped color value at a single pixel` + | :sg:`get_at_mapped((x, y)) -> Color` + + Return the integer value of the given pixel. If the pixel position is + outside the area of the Surface an ``IndexError`` exception will be + raised. + + This method is intended for pygame unit testing. It unlikely has any use + in an application. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.9.2 + + .. ## Surface.get_at_mapped ## + + .. method:: get_palette + + | :sl:`get the color index palette for an 8-bit Surface` + | :sg:`get_palette() -> [RGB, RGB, RGB, ...]` + + Return a list of up to 256 color elements that represent the indexed + colors used in an 8-bit Surface. The returned list is a copy of the + palette, and changes will have no effect on the Surface. + + Returning a list of ``Color(with length 3)`` instances instead of tuples. + + .. versionadded:: 1.9 + + .. ## Surface.get_palette ## + + .. method:: get_palette_at + + | :sl:`get the color for a single entry in a palette` + | :sg:`get_palette_at(index) -> RGB` + + Returns the red, green, and blue color values for a single index in a + Surface palette. The index should be a value from 0 to 255. + + .. versionadded:: 1.9 + Returning ``Color(with length 3)`` instance instead of a tuple. + + .. ## Surface.get_palette_at ## + + .. method:: set_palette + + | :sl:`set the color palette for an 8-bit Surface` + | :sg:`set_palette([RGB, RGB, RGB, ...]) -> None` + + Set the full palette for an 8-bit Surface. This will replace the colors in + the existing palette. A partial palette can be passed and only the first + colors in the original palette will be changed. + + This function has no effect on a Surface with more than 8-bits per pixel. + + .. ## Surface.set_palette ## + + .. method:: set_palette_at + + | :sl:`set the color for a single index in an 8-bit Surface palette` + | :sg:`set_palette_at(index, RGB) -> None` + + Set the palette value for a single entry in a Surface palette. The index + should be a value from 0 to 255. + + This function has no effect on a Surface with more than 8-bits per pixel. + + .. ## Surface.set_palette_at ## + + .. method:: map_rgb + + | :sl:`convert a color into a mapped color value` + | :sg:`map_rgb(Color) -> mapped_int` + + Convert an ``RGBA`` color into the mapped integer value for this Surface. + The returned integer will contain no more bits than the bit depth of the + Surface. Mapped color values are not often used inside pygame, but can be + passed to most functions that require a Surface and a color. + + See the Surface object documentation for more information about colors + and pixel formats. + + .. ## Surface.map_rgb ## + + .. method:: unmap_rgb + + | :sl:`convert a mapped integer color value into a Color` + | :sg:`unmap_rgb(mapped_int) -> Color` + + Convert an mapped integer color into the ``RGB`` color components for + this Surface. Mapped color values are not often used inside pygame, but + can be passed to most functions that require a Surface and a color. + + See the Surface object documentation for more information about colors + and pixel formats. + + .. ## Surface.unmap_rgb ## + + .. method:: set_clip + + | :sl:`set the current clipping area of the Surface` + | :sg:`set_clip(rect) -> None` + | :sg:`set_clip(None) -> None` + + Each Surface has an active clipping area. This is a rectangle that + represents the only pixels on the Surface that can be modified. If + ``None`` is passed for the rectangle the full Surface will be available + for changes. + + The clipping area is always restricted to the area of the Surface itself. + If the clip rectangle is too large it will be shrunk to fit inside the + Surface. + + .. ## Surface.set_clip ## + + .. method:: get_clip + + | :sl:`get the current clipping area of the Surface` + | :sg:`get_clip() -> Rect` + + Return a rectangle of the current clipping area. The Surface will always + return a valid rectangle that will never be outside the bounds of the + image. If the Surface has had ``None`` set for the clipping area, the + Surface will return a rectangle with the full area of the Surface. + + .. ## Surface.get_clip ## + + .. method:: subsurface + + | :sl:`create a new surface that references its parent` + | :sg:`subsurface(Rect) -> Surface` + + Returns a new Surface that shares its pixels with its new parent. The new + Surface is considered a child of the original. Modifications to either + Surface pixels will effect each other. Surface information like clipping + area and color keys are unique to each Surface. + + The new Surface will inherit the palette, color key, and alpha settings + from its parent. + + It is possible to have any number of subsurfaces and subsubsurfaces on + the parent. It is also possible to subsurface the display Surface if the + display mode is not hardware accelerated. + + See :meth:`get_offset()` and :meth:`get_parent()` to learn more + about the state of a subsurface. + + A subsurface will have the same class as the parent surface. + + .. ## Surface.subsurface ## + + .. method:: get_parent + + | :sl:`find the parent of a subsurface` + | :sg:`get_parent() -> Surface` + + Returns the parent Surface of a subsurface. If this is not a subsurface + then ``None`` will be returned. + + .. ## Surface.get_parent ## + + .. method:: get_abs_parent + + | :sl:`find the top level parent of a subsurface` + | :sg:`get_abs_parent() -> Surface` + + Returns the parent Surface of a subsurface. If this is not a subsurface + then this surface will be returned. + + .. ## Surface.get_abs_parent ## + + .. method:: get_offset + + | :sl:`find the position of a child subsurface inside a parent` + | :sg:`get_offset() -> (x, y)` + + Get the offset position of a child subsurface inside of a parent. If the + Surface is not a subsurface this will return (0, 0). + + .. ## Surface.get_offset ## + + .. method:: get_abs_offset + + | :sl:`find the absolute position of a child subsurface inside its top level parent` + | :sg:`get_abs_offset() -> (x, y)` + + Get the offset position of a child subsurface inside of its top level + parent Surface. If the Surface is not a subsurface this will return (0, + 0). + + .. ## Surface.get_abs_offset ## + + .. method:: get_size + + | :sl:`get the dimensions of the Surface` + | :sg:`get_size() -> (width, height)` + + Return the width and height of the Surface in pixels. + + .. ## Surface.get_size ## + + .. method:: get_width + + | :sl:`get the width of the Surface` + | :sg:`get_width() -> width` + + Return the width of the Surface in pixels. + + .. ## Surface.get_width ## + + .. method:: get_height + + | :sl:`get the height of the Surface` + | :sg:`get_height() -> height` + + Return the height of the Surface in pixels. + + .. ## Surface.get_height ## + + .. method:: get_rect + + | :sl:`get the rectangular area of the Surface` + | :sg:`get_rect(\**kwargs) -> Rect` + + Returns a new rectangle covering the entire surface. This rectangle will + always start at (0, 0) with a width and height the same size as the image. + + You can pass keyword argument values to this function. These named values + will be applied to the attributes of the Rect before it is returned. An + example would be ``mysurf.get_rect(center=(100, 100))`` to create a + rectangle for the Surface centered at a given position. + + .. ## Surface.get_rect ## + + .. method:: get_bitsize + + | :sl:`get the bit depth of the Surface pixel format` + | :sg:`get_bitsize() -> int` + + Returns the number of bits used to represent each pixel. This value may + not exactly fill the number of bytes used per pixel. For example a 15 bit + Surface still requires a full 2 bytes. + + .. ## Surface.get_bitsize ## + + .. method:: get_bytesize + + | :sl:`get the bytes used per Surface pixel` + | :sg:`get_bytesize() -> int` + + Return the number of bytes used per pixel. + + .. ## Surface.get_bytesize ## + + .. method:: get_flags + + | :sl:`get the additional flags used for the Surface` + | :sg:`get_flags() -> int` + + Returns a set of current Surface features. Each feature is a bit in the + flags bitmask. Typical flags are ``RLEACCEL``, ``SRCALPHA``, and + ``SRCCOLORKEY``. + + Here is a more complete list of flags. A full list can be found in + ``SDL_video.h`` + + :: + + SWSURFACE 0x00000000 # Surface is in system memory + HWSURFACE 0x00000001 # (obsolete in pygame 2) Surface is in video memory + ASYNCBLIT 0x00000004 # (obsolete in pygame 2) Use asynchronous blits if possible + + See :func:`pygame.display.set_mode()` for flags exclusive to the + display surface. + + Used internally (read-only) + + :: + + HWACCEL 0x00000100 # Blit uses hardware acceleration + SRCCOLORKEY 0x00001000 # Blit uses a source color key + RLEACCELOK 0x00002000 # Private flag + RLEACCEL 0x00004000 # Surface is RLE encoded + SRCALPHA 0x00010000 # Blit uses source alpha blending + PREALLOC 0x01000000 # Surface uses preallocated memory + + .. ## Surface.get_flags ## + + .. method:: get_pitch + + | :sl:`get the number of bytes used per Surface row` + | :sg:`get_pitch() -> int` + + Return the number of bytes separating each row in the Surface. Surfaces + in video memory are not always linearly packed. Subsurfaces will also + have a larger pitch than their real width. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_pitch ## + + .. method:: get_masks + + | :sl:`the bitmasks needed to convert between a color and a mapped integer` + | :sg:`get_masks() -> (R, G, B, A)` + + Returns the bitmasks used to isolate each color in a mapped integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_masks ## + + .. method:: set_masks + + | :sl:`set the bitmasks needed to convert between a color and a mapped integer` + | :sg:`set_masks((r,g,b,a)) -> None` + + This is not needed for normal pygame usage. + + .. note:: Starting in pygame 2.0, the masks are read-only and + accordingly this method will raise a TypeError if called. + + .. deprecated:: 2.0.0 + + .. versionadded:: 1.8.1 + + .. ## Surface.set_masks ## + + .. method:: get_shifts + + | :sl:`the bit shifts needed to convert between a color and a mapped integer` + | :sg:`get_shifts() -> (R, G, B, A)` + + Returns the pixel shifts need to convert between each color and a mapped + integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_shifts ## + + .. method:: set_shifts + + | :sl:`sets the bit shifts needed to convert between a color and a mapped integer` + | :sg:`set_shifts((r,g,b,a)) -> None` + + This is not needed for normal pygame usage. + + .. note:: Starting in pygame 2.0, the shifts are read-only and + accordingly this method will raise a TypeError if called. + + .. deprecated:: 2.0.0 + + .. versionadded:: 1.8.1 + + .. ## Surface.set_shifts ## + + .. method:: get_losses + + | :sl:`the significant bits used to convert between a color and a mapped integer` + | :sg:`get_losses() -> (R, G, B, A)` + + Return the least significant number of bits stripped from each color in a + mapped integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_losses ## + + .. method:: get_bounding_rect + + | :sl:`find the smallest rect containing data` + | :sg:`get_bounding_rect(min_alpha = 1) -> Rect` + + Returns the smallest rectangular region that contains all the pixels in + the surface that have an alpha value greater than or equal to the minimum + alpha value. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.8 + + .. ## Surface.get_bounding_rect ## + + .. method:: get_view + + | :sl:`return a buffer view of the Surface's pixels.` + | :sg:`get_view(='2') -> BufferProxy` + + Return an object which exports a surface's internal pixel buffer as + a C level array struct, Python level array interface or a C level + buffer interface. The new buffer protocol is supported. + + The kind argument is the length 1 string '0', '1', '2', '3', + 'r', 'g', 'b', or 'a'. The letters are case insensitive; + 'A' will work as well. The argument can be either a Unicode or byte (char) + string. The default is '2'. + + '0' returns a contiguous unstructured bytes view. No surface shape + information is given. A ``ValueError`` is raised if the surface's pixels + are discontinuous. + + '1' returns a (surface-width * surface-height) array of continuous + pixels. A ``ValueError`` is raised if the surface pixels are + discontinuous. + + '2' returns a (surface-width, surface-height) array of raw pixels. + The pixels are surface-bytesize-d unsigned integers. The pixel format is + surface specific. The 3 byte unsigned integers of 24 bit surfaces are + unlikely accepted by anything other than other pygame functions. + + '3' returns a (surface-width, surface-height, 3) array of ``RGB`` color + components. Each of the red, green, and blue components are unsigned + bytes. Only 24-bit and 32-bit surfaces are supported. The color + components must be in either ``RGB`` or ``BGR`` order within the pixel. + + 'r' for red, 'g' for green, 'b' for blue, and 'a' for alpha return a + (surface-width, surface-height) view of a single color component within a + surface: a color plane. Color components are unsigned bytes. Both 24-bit + and 32-bit surfaces support 'r', 'g', and 'b'. Only 32-bit surfaces with + ``SRCALPHA`` support 'a'. + + The surface is locked only when an exposed interface is accessed. + For new buffer interface accesses, the surface is unlocked once the + last buffer view is released. For array interface and old buffer + interface accesses, the surface remains locked until the BufferProxy + object is released. + + .. versionadded:: 1.9.2 + + .. method:: get_buffer + + | :sl:`acquires a buffer object for the pixels of the Surface.` + | :sg:`get_buffer() -> BufferProxy` + + Return a buffer object for the pixels of the Surface. The buffer can be + used for direct pixel access and manipulation. Surface pixel data is + represented as an unstructured block of memory, with a start address + and length in bytes. The data need not be contiguous. Any gaps are + included in the length, but otherwise ignored. + + This method implicitly locks the Surface. The lock will be released when + the returned :mod:`pygame.BufferProxy` object is garbage collected. + + .. versionadded:: 1.8 + + .. ## Surface.get_buffer ## + + .. attribute:: _pixels_address + + | :sl:`pixel buffer address` + | :sg:`_pixels_address -> int` + + The starting address of the surface's raw pixel bytes. + + .. versionadded:: 1.9.2 + + .. method:: premul_alpha + + | :sl:`returns a copy of the surface with the RGB channels pre-multiplied by the alpha channel.` + | :sg:`premul_alpha() -> Surface` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave premul_alpha feedback with authors `_ + + Returns a copy of the initial surface with the red, green and blue color channels multiplied + by the alpha channel. This is intended to make it easier to work with the BLEND_PREMULTIPLED + blend mode flag of the blit() method. Surfaces which have called this method will only look + correct after blitting if the BLEND_PREMULTIPLED special flag is used. + + It is worth noting that after calling this method, methods that return the colour of a pixel + such as get_at() will return the alpha multiplied colour values. It is not possible to fully + reverse an alpha multiplication of the colours in a surface as integer colour channel data + is generally reduced by the operation (e.g. 255 x 0 = 0, from there it is not possible to reconstruct + the original 255 from just the two remaining zeros in the colour and alpha channels). + + If you call this method, and then call it again, it will multiply the colour channels by the alpha channel + twice. There are many possible ways to obtain a surface with the colour channels pre-multiplied by the + alpha channel in pygame, and it is not possible to tell the difference just from the information in the pixels. + It is completely possible to have two identical surfaces - one intended for pre-multiplied alpha blending and + one intended for normal blending. For this reason we do not store state on surfaces intended for pre-multiplied + alpha blending. + + Surfaces without an alpha channel cannot use this method and will return an error if you use + it on them. It is best used on 32 bit surfaces (the default on most platforms) as the blitting + on these surfaces can be accelerated by SIMD versions of the pre-multiplied blitter. + + In general pre-multiplied alpha blitting is faster then 'straight alpha' blitting and produces + superior results when blitting an alpha surface onto another surface with alpha - assuming both + surfaces contain pre-multiplied alpha colours. + + .. versionadded:: 2.2.0 + + .. ## Surface.premul_alpha ## + + .. ## pygame.Surface ## + + diff --git a/docs/ref/surfarray.rst b/docs/ref/surfarray.rst new file mode 100644 index 0000000..c29723a --- /dev/null +++ b/docs/ref/surfarray.rst @@ -0,0 +1,337 @@ +.. include:: common.txt + +:mod:`pygame.surfarray` +======================= + +.. module:: pygame.surfarray + :synopsis: pygame module for accessing surface pixel data using array interfaces + +| :sl:`pygame module for accessing surface pixel data using array interfaces` + +Functions to convert between NumPy arrays and Surface objects. This module +will only be functional when pygame can use the external NumPy package. +If NumPy can't be imported, ``surfarray`` becomes a ``MissingModule`` object. + +Every pixel is stored as a single integer value to represent the red, green, +and blue colors. The 8-bit images use a value that looks into a colormap. Pixels +with higher depth use a bit packing process to place three or four values into +a single number. + +The arrays are indexed by the ``X`` axis first, followed by the ``Y`` axis. +Arrays that treat the pixels as a single integer are referred to as 2D arrays. +This module can also separate the red, green, and blue color values into +separate indices. These types of arrays are referred to as 3D arrays, and the +last index is 0 for red, 1 for green, and 2 for blue. + +The pixels of a 2D array as returned by :func:`array2d` and :func:`pixels2d` +are mapped to the specific surface. Use :meth:`pygame.Surface.unmap_rgb` +to convert to a color, and :meth:`pygame.Surface.map_rgb` to get the surface +specific pixel value of a color. Integer pixel values can only be used directly +between surfaces with matching pixel layouts (see :class:`pygame.Surface`). + +All functions that refer to "array" will copy the surface information to a new +numpy array. All functions that refer to "pixels" will directly reference the +pixels from the surface and any changes performed to the array will make changes +in the surface. As this last functions share memory with the surface, this one +will be locked during the lifetime of the array. + +.. function:: array2d + + | :sl:`Copy pixels into a 2d array` + | :sg:`array2d(Surface) -> array` + + Copy the :meth:`mapped ` (raw) pixels from a Surface + into a 2D array. + The bit depth of the surface will control the size of the integer values, + and will work for any type of pixel format. + + This function will temporarily lock the Surface as pixels are copied + (see the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array2d ## + +.. function:: pixels2d + + | :sl:`Reference pixels into a 2d array` + | :sg:`pixels2d(Surface) -> array` + + Create a new 2D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + Pixels from a 24-bit Surface cannot be referenced, but all other Surface bit + depths can. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels2d ## + +.. function:: array3d + + | :sl:`Copy pixels into a 3d array` + | :sg:`array3d(Surface) -> array` + + Copy the pixels from a Surface into a 3D array. The bit depth of the surface + will control the size of the integer values, and will work for any type of + pixel format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array3d ## + +.. function:: pixels3d + + | :sl:`Reference pixels into a 3d array` + | :sg:`pixels3d(Surface) -> array` + + Create a new 3D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + This will only work on Surfaces that have 24-bit or 32-bit formats. Lower + pixel formats cannot be referenced. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels3d ## + +.. function:: array_alpha + + | :sl:`Copy pixel alphas into a 2d array` + | :sg:`array_alpha(Surface) -> array` + + Copy the pixel alpha values (degree of transparency) from a Surface into a + 2D array. This will work for any type of Surface format. Surfaces without a + pixel alpha will return an array with all opaque values. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array_alpha ## + +.. function:: pixels_alpha + + | :sl:`Reference pixel alphas into a 2d array` + | :sg:`pixels_alpha(Surface) -> array` + + Create a new 2D array that directly references the alpha values (degree of + transparency) in a Surface. Any changes to the array will affect the pixels + in the Surface. This is a fast operation since no data is copied. + + This can only work on 32-bit Surfaces with a per-pixel alpha value. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_alpha ## + +.. function:: array_red + + | :sl:`Copy red pixels into a 2d array` + | :sg:`array_red(Surface) -> array` + + Copy the pixel red values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_red ## + +.. function:: pixels_red + + | :sl:`Reference pixel red into a 2d array.` + | :sg:`pixels_red (Surface) -> array` + + Create a new 2D array that directly references the red values in a Surface. + Any changes to the array will affect the pixels in the Surface. This is a + fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_red ## + +.. function:: array_green + + | :sl:`Copy green pixels into a 2d array` + | :sg:`array_green(Surface) -> array` + + Copy the pixel green values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_green ## + +.. function:: pixels_green + + | :sl:`Reference pixel green into a 2d array.` + | :sg:`pixels_green (Surface) -> array` + + Create a new 2D array that directly references the green values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_green ## + +.. function:: array_blue + + | :sl:`Copy blue pixels into a 2d array` + | :sg:`array_blue(Surface) -> array` + + Copy the pixel blue values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_blue ## + +.. function:: pixels_blue + + | :sl:`Reference pixel blue into a 2d array.` + | :sg:`pixels_blue (Surface) -> array` + + Create a new 2D array that directly references the blue values in a Surface. + Any changes to the array will affect the pixels in the Surface. This is a + fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_blue ## + +.. function:: array_colorkey + + | :sl:`Copy the colorkey values into a 2d array` + | :sg:`array_colorkey(Surface) -> array` + + Create a new array with the colorkey transparency value from each pixel. If + the pixel matches the colorkey it will be fully transparent; otherwise it + will be fully opaque. + + This will work on any type of Surface format. If the image has no colorkey a + solid opaque array will be returned. + + This function will temporarily lock the Surface as pixels are copied. + + .. ## pygame.surfarray.array_colorkey ## + +.. function:: make_surface + + | :sl:`Copy an array to a new surface` + | :sg:`make_surface(array) -> Surface` + + Create a new Surface that best resembles the data and format on the array. + The array can be 2D or 3D with any sized integer values. Function + make_surface uses the array struct interface to acquire array properties, + so is not limited to just NumPy arrays. See :mod:`pygame.pixelcopy`. + + New in pygame 1.9.2: array struct interface support. + + .. ## pygame.surfarray.make_surface ## + +.. function:: blit_array + + | :sl:`Blit directly from a array values` + | :sg:`blit_array(Surface, array) -> None` + + Directly copy values from an array into a Surface. This is faster than + converting the array into a Surface and blitting. The array must be the same + dimensions as the Surface and will completely replace all pixel values. Only + integer, ASCII character and record arrays are accepted. + + This function will temporarily lock the Surface as the new values are + copied. + + .. ## pygame.surfarray.blit_array ## + +.. function:: map_array + + | :sl:`Map a 3d array into a 2d array` + | :sg:`map_array(Surface, array3d) -> array2d` + + Convert a 3D array into a 2D array. This will use the given Surface format + to control the conversion. Palette surface formats are supported for NumPy + arrays. + + .. ## pygame.surfarray.map_array ## + +.. function:: use_arraytype + + | :sl:`Sets the array system to be used for surface arrays` + | :sg:`use_arraytype (arraytype) -> None` + + DEPRECATED: Uses the requested array type for the module functions. + The only supported arraytype is ``'numpy'``. Other values will raise + ValueError. Using this function will raise a ``DeprecationWarning``. + + .. ## pygame.surfarray.use_arraytype ## + +.. function:: get_arraytype + + | :sl:`Gets the currently active array type.` + | :sg:`get_arraytype () -> str` + + DEPRECATED: Returns the currently active array type. This will be a value of the + ``get_arraytypes()`` tuple and indicates which type of array module is used + for the array creation. Using this function will raise a ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.surfarray.get_arraytype ## + +.. function:: get_arraytypes + + | :sl:`Gets the array system types currently supported.` + | :sg:`get_arraytypes () -> tuple` + + DEPRECATED: Checks, which array systems are available and returns them as a tuple of + strings. The values of the tuple can be used directly in the + :func:`pygame.surfarray.use_arraytype` () method. If no supported array + system could be found, None will be returned. Using this function will raise a + ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.surfarray.get_arraytypes ## + +.. ## pygame.surfarray ## diff --git a/docs/ref/tests.rst b/docs/ref/tests.rst new file mode 100644 index 0000000..88184f6 --- /dev/null +++ b/docs/ref/tests.rst @@ -0,0 +1,113 @@ +.. include:: common.txt + +:mod:`pygame.tests` +=================== + +.. module:: pygame.tests + :synopsis: Pygame unit test suite package + +| :sl:`Pygame unit test suite package` + +A quick way to run the test suite package from the command line is to import +the go submodule with the Python -m option: + +:: + + python -m pygame.tests [] + +Command line option --help displays a usage message. Available options +correspond to the :func:`pygame.tests.run` arguments. + +The xxxx_test submodules of the tests package are unit test suites for +individual parts of pygame. Each can also be run as a main program. This is +useful if the test, such as cdrom_test, is interactive. + +For pygame development the test suite can be run from a pygame distribution +root directory. Program ``run_tests.py`` is provided for convenience, though +test/go.py can be run directly. + +Module level tags control which modules are included in a unit test run. Tags +are assigned to a unit test module with a corresponding _tags.py module. +The tags module has the global __tags__, a list of tag names. For example, +``cdrom_test.py`` has a tag file ``cdrom_tags.py`` containing a tags list that +has the 'interactive' string. The 'interactive' tag indicates ``cdrom_test.py`` +expects user input. It is excluded from a ``run_tests.py`` or +``pygame.tests.go`` run. + +Two other tags that are excluded are 'ignore' and 'subprocess_ignore'. These +two tags indicate unit tests that will not run on a particular platform, or +for which no corresponding pygame module is available. + +The test runner will list each excluded module along with the tag responsible. + +.. function:: run + + | :sl:`Run the pygame unit test suite` + | :sg:`run(*args, **kwds) -> tuple` + + Positional arguments (optional): + + :: + + The names of tests to include. If omitted then all tests are run. Test names + need not include the trailing '_test'. + + Keyword arguments: + + :: + + incomplete - fail incomplete tests (default False) + nosubprocess - run all test suites in the current process + (default False, use separate subprocesses) + dump - dump failures/errors as dict ready to eval (default False) + file - if provided, the name of a file into which to dump failures/errors + timings - if provided, the number of times to run each individual test to + get an average run time (default is run each test once) + exclude - A list of TAG names to exclude from the run + show_output - show silenced stderr/stdout on errors (default False) + all - dump all results, not just errors (default False) + randomize - randomize order of tests (default False) + seed - if provided, a seed randomizer integer + multi_thread - if provided, the number of THREADS in which to run + subprocessed tests + time_out - if subprocess is True then the time limit in seconds before + killing a test (default 30) + fake - if provided, the name of the fake tests package in the + run_tests__tests subpackage to run instead of the normal + pygame tests + python - the path to a python executable to run subprocessed tests + (default sys.executable) + + Return value: + + :: + + A tuple of total number of tests run, dictionary of error information. + The dictionary is empty if no errors were recorded. + + By default individual test modules are run in separate subprocesses. This + recreates normal pygame usage where ``pygame.init()`` and ``pygame.quit()`` + are called only once per program execution, and avoids unfortunate + interactions between test modules. + + A time limit is placed on test execution ensuring that any frozen tests + processes are killed when their time allotment is expired. Use the single + process option if threading is not working properly or if tests are taking + too long. It is not guaranteed that all tests will pass in single process + mode. + + Tests are run in a randomized order if the randomize argument is True or a + seed argument is provided. If no seed integer is provided then the system + time is used for the randomization seed value. + + Individual test modules may have a __tags__ attribute, a list of tag strings + used to selectively omit modules from a run. By default only 'interactive' + modules such as cdrom_test are ignored. An interactive module must be run + from the console as a Python program. + + This function can only be called once per Python session. It is not + reentrant. + + .. ## pygame.tests.run ## + +.. ## pygame.tests ## diff --git a/docs/ref/time.rst b/docs/ref/time.rst new file mode 100644 index 0000000..59e0999 --- /dev/null +++ b/docs/ref/time.rst @@ -0,0 +1,165 @@ +.. include:: common.txt + +:mod:`pygame.time` +================== + +.. module:: pygame.time + :synopsis: pygame module for monitoring time + +| :sl:`pygame module for monitoring time` + +Times in pygame are represented in milliseconds (1/1000 seconds). Most +platforms have a limited time resolution of around 10 milliseconds. This +resolution, in milliseconds, is given in the ``TIMER_RESOLUTION`` constant. + +.. function:: get_ticks + + | :sl:`get the time in milliseconds` + | :sg:`get_ticks() -> milliseconds` + + Return the number of milliseconds since ``pygame.init()`` was called. Before + pygame is initialized this will always be 0. + + .. ## pygame.time.get_ticks ## + +.. function:: wait + + | :sl:`pause the program for an amount of time` + | :sg:`wait(milliseconds) -> time` + + Will pause for a given number of milliseconds. This function sleeps the + process to share the processor with other programs. A program that waits for + even a few milliseconds will consume very little processor time. It is + slightly less accurate than the ``pygame.time.delay()`` function. + + This returns the actual number of milliseconds used. + + .. ## pygame.time.wait ## + +.. function:: delay + + | :sl:`pause the program for an amount of time` + | :sg:`delay(milliseconds) -> time` + + Will pause for a given number of milliseconds. This function will use the + processor (rather than sleeping) in order to make the delay more accurate + than ``pygame.time.wait()``. + + This returns the actual number of milliseconds used. + + .. ## pygame.time.delay ## + +.. function:: set_timer + + | :sl:`repeatedly create an event on the event queue` + | :sg:`set_timer(event, millis) -> None` + | :sg:`set_timer(event, millis, loops=0) -> None` + + Set an event to appear on the event queue every given number of milliseconds. + The first event will not appear until the amount of time has passed. + + The ``event`` attribute can be a ``pygame.event.Event`` object or an integer + type that denotes an event. + + ``loops`` is an integer that denotes the number of events posted. If 0 (default) + then the events will keep getting posted, unless explicitly stopped. + + To disable the timer for such an event, call the function again with the same + event argument with ``millis`` argument set to 0. + + It is also worth mentioning that a particular event type can only be put on a + timer once. In other words, there cannot be two timers for the same event type. + Setting an event timer for a particular event discards the old one for that + event type. + + ``loops`` replaces the ``once`` argument, and this does not break backward + compatibility + + .. versionadded:: 2.0.0.dev3 once argument added. + .. versionchanged:: 2.0.1 event argument supports ``pygame.event.Event`` object + .. versionadded:: 2.0.1 added loops argument to replace once argument + + .. ## pygame.time.set_timer ## + +.. class:: Clock + + | :sl:`create an object to help track time` + | :sg:`Clock() -> Clock` + + Creates a new Clock object that can be used to track an amount of time. The + clock also provides several functions to help control a game's framerate. + + .. method:: tick + + | :sl:`update the clock` + | :sg:`tick(framerate=0) -> milliseconds` + + This method should be called once per frame. It will compute how many + milliseconds have passed since the previous call. + + If you pass the optional framerate argument the function will delay to + keep the game running slower than the given ticks per second. This can be + used to help limit the runtime speed of a game. By calling + ``Clock.tick(40)`` once per frame, the program will never run at more + than 40 frames per second. + + Note that this function uses SDL_Delay function which is not accurate on + every platform, but does not use much CPU. Use tick_busy_loop if you want + an accurate timer, and don't mind chewing CPU. + + .. ## Clock.tick ## + + .. method:: tick_busy_loop + + | :sl:`update the clock` + | :sg:`tick_busy_loop(framerate=0) -> milliseconds` + + This method should be called once per frame. It will compute how many + milliseconds have passed since the previous call. + + If you pass the optional framerate argument the function will delay to + keep the game running slower than the given ticks per second. This can be + used to help limit the runtime speed of a game. By calling + ``Clock.tick_busy_loop(40)`` once per frame, the program will never run at + more than 40 frames per second. + + Note that this function uses :func:`pygame.time.delay`, which uses lots + of CPU in a busy loop to make sure that timing is more accurate. + + .. versionadded:: 1.8 + + .. ## Clock.tick_busy_loop ## + + .. method:: get_time + + | :sl:`time used in the previous tick` + | :sg:`get_time() -> milliseconds` + + The number of milliseconds that passed between the previous two calls to + ``Clock.tick()``. + + .. ## Clock.get_time ## + + .. method:: get_rawtime + + | :sl:`actual time used in the previous tick` + | :sg:`get_rawtime() -> milliseconds` + + Similar to ``Clock.get_time()``, but does not include any time used + while ``Clock.tick()`` was delaying to limit the framerate. + + .. ## Clock.get_rawtime ## + + .. method:: get_fps + + | :sl:`compute the clock framerate` + | :sg:`get_fps() -> float` + + Compute your game's framerate (in frames per second). It is computed by + averaging the last ten calls to ``Clock.tick()``. + + .. ## Clock.get_fps ## + + .. ## pygame.time.Clock ## + +.. ## pygame.time ## diff --git a/docs/ref/touch.rst b/docs/ref/touch.rst new file mode 100644 index 0000000..320da05 --- /dev/null +++ b/docs/ref/touch.rst @@ -0,0 +1,66 @@ +.. include:: common.txt + +:mod:`pygame._sdl2.touch` +========================= + +.. module:: pygame._sdl2.touch + :synopsis: pygame module to work with touch input + +| :sl:`pygame module to work with touch input` + +.. versionadded:: 2 This module requires SDL2. + +.. function:: get_num_devices + + | :sl:`get the number of touch devices` + | :sg:`get_num_devices() -> int` + + Return the number of available touch devices. + + .. ## pygame._sdl2.touch.get_num_devices ## + +.. function:: get_device + + | :sl:`get the a touch device id for a given index` + | :sg:`get_device(index) -> touchid` + + :param int index: This number is at least 0 and less than the + :func:`number of devices `. + + Return an integer id associated with the given ``index``. + + .. ## pygame._sdl2.touch.get_device ## + +.. function:: get_num_fingers + + | :sl:`the number of active fingers for a given touch device` + | :sg:`get_num_fingers(touchid) -> int` + + Return the number of fingers active for the touch device + whose id is `touchid`. + + .. ## pygame._sdl2.touch.get_num_fingers ## + +.. function:: get_finger + + | :sl:`get information about an active finger` + | :sg:`get_finger(touchid, index) -> int` + + :param int touchid: The touch device id. + :param int index: The index of the finger to return + information about, between 0 and the + :func:`number of active fingers `. + + Return a dict for the finger ``index`` active on ``touchid``. + The dict contains these keys: + + :: + + id the id of the finger (an integer). + x the normalized x position of the finger, between 0 and 1. + y the normalized y position of the finger, between 0 and 1. + pressure the amount of pressure applied by the finger, between 0 and 1. + + .. ## pygame._sdl2.touch.get_finger ## + +.. ## pygame._sdl2.touch ## diff --git a/docs/ref/transform.rst b/docs/ref/transform.rst new file mode 100644 index 0000000..91a3a8f --- /dev/null +++ b/docs/ref/transform.rst @@ -0,0 +1,325 @@ +.. include:: common.txt + +:mod:`pygame.transform` +======================= + +.. module:: pygame.transform + :synopsis: pygame module to transform surfaces + +| :sl:`pygame module to transform surfaces` + +A Surface transform is an operation that moves or resizes the pixels. All these +functions take a Surface to operate on and return a new Surface with the +results. + +Some of the transforms are considered destructive. These means every time they +are performed they lose pixel data. Common examples of this are resizing and +rotating. For this reason, it is better to re-transform the original surface +than to keep transforming an image multiple times. (For example, suppose you +are animating a bouncing spring which expands and contracts. If you applied the +size changes incrementally to the previous images, you would lose detail. +Instead, always begin with the original image and scale to the desired size.) + +.. versionchanged:: 2.0.2 transform functions now support keyword arguments. + +.. function:: flip + + | :sl:`flip vertically and horizontally` + | :sg:`flip(surface, flip_x, flip_y) -> Surface` + + This can flip a Surface either vertically, horizontally, or both. + The arguments ``flip_x`` and ``flip_y`` are booleans that control whether + to flip each axis. Flipping a Surface is non-destructive and returns a new + Surface with the same dimensions. + + .. ## pygame.transform.flip ## + +.. function:: scale + + | :sl:`resize to new resolution` + | :sg:`scale(surface, size, dest_surface=None) -> Surface` + + Resizes the Surface to a new size, given as (width, height). + This is a fast scale operation that does not sample the results. + + An optional destination surface can be used, rather than have it create a + new one. This is quicker if you want to repeatedly scale something. However + the destination must be the same size as the size (width, height) passed in. Also + the destination surface must be the same format. + + .. ## pygame.transform.scale ## + +.. function:: scale_by + + | :sl:`resize to new resolution, using scalar(s)` + | :sg:`scale_by(surface, factor, dest_surface=None) -> Surface` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave scale_by feedback with authors `_ + + Same as :func:`scale()`, but scales by some factor, rather than taking + the new size explicitly. For example, :code:`transform.scale_by(surf, 3)` + will triple the size of the surface in both dimensions. Optionally, the + scale factor can be a sequence of two numbers, controlling x and y scaling + separately. For example, :code:`transform.scale_by(surf, (2, 1))` doubles + the image width but keeps the height the same. + + .. versionadded:: 2.1.3 + + .. ## pygame.transform.scale_by ## + +.. function:: rotate + + | :sl:`rotate an image` + | :sg:`rotate(surface, angle) -> Surface` + + Unfiltered counterclockwise rotation. The angle argument represents degrees + and can be any floating point value. Negative angle amounts will rotate + clockwise. + + Unless rotating by 90 degree increments, the image will be padded larger to + hold the new size. If the image has pixel alphas, the padded area will be + transparent. Otherwise pygame will pick a color that matches the Surface + colorkey or the topleft pixel value. + + .. ## pygame.transform.rotate ## + +.. function:: rotozoom + + | :sl:`filtered scale and rotation` + | :sg:`rotozoom(surface, angle, scale) -> Surface` + + This is a combined scale and rotation transform. The resulting Surface will + be a filtered 32-bit Surface. The scale argument is a floating point value + that will be multiplied by the current resolution. The angle argument is a + floating point value that represents the counterclockwise degrees to rotate. + A negative rotation angle will rotate clockwise. + + .. ## pygame.transform.rotozoom ## + +.. function:: scale2x + + | :sl:`specialized image doubler` + | :sg:`scale2x(surface, dest_surface=None) -> Surface` + + This will return a new image that is double the size of the original. It + uses the AdvanceMAME Scale2X algorithm which does a 'jaggie-less' scale of + bitmap graphics. + + This really only has an effect on simple images with solid colors. On + photographic and antialiased images it will look like a regular unfiltered + scale. + + An optional destination surface can be used, rather than have it create a + new one. This is quicker if you want to repeatedly scale something. However + the destination must be twice the size of the source surface passed in. Also + the destination surface must be the same format. + + .. ## pygame.transform.scale2x ## + +.. function:: smoothscale + + | :sl:`scale a surface to an arbitrary size smoothly` + | :sg:`smoothscale(surface, size, dest_surface=None) -> Surface` + + Uses one of two different algorithms for scaling each dimension of the input + surface as required. For shrinkage, the output pixels are area averages of + the colors they cover. For expansion, a bilinear filter is used. For the + x86-64 and i686 architectures, optimized ``MMX`` routines are included and + will run much faster than other machine types. The size is a 2 number + sequence for (width, height). This function only works for 24-bit or 32-bit + surfaces. An exception will be thrown if the input surface bit depth is less + than 24. + + .. versionadded:: 1.8 + + .. ## pygame.transform.smoothscale ## + +.. function:: smoothscale_by + + | :sl:`resize to new resolution, using scalar(s)` + | :sg:`smoothscale_by(surface, factor, dest_surface=None) -> Surface` + + **Experimental:** feature still in development available for testing and feedback. It may change. + `Please leave smoothscale_by feedback with authors `_ + + Same as :func:`smoothscale()`, but scales by some factor, rather than + taking the new size explicitly. For example, + :code:`transform.smoothscale_by(surf, 3)` will triple the size of the + surface in both dimensions. Optionally, the scale factor can be a sequence + of two numbers, controlling x and y scaling separately. For example, + :code:`transform.smoothscale_by(surf, (2, 1))` doubles the image width but + keeps the height the same. + + .. versionadded:: 2.1.3 + + .. ## pygame.transform.smoothscale_by ## + +.. function:: get_smoothscale_backend + + | :sl:`return smoothscale filter version in use: 'GENERIC', 'MMX', or 'SSE'` + | :sg:`get_smoothscale_backend() -> string` + + Shows whether or not smoothscale is using ``MMX`` or ``SSE`` acceleration. + If no acceleration is available then "GENERIC" is returned. For a x86 + processor the level of acceleration to use is determined at runtime. + + This function is provided for pygame testing and debugging. + + .. ## pygame.transform.get_smoothscale_backend ## + +.. function:: set_smoothscale_backend + + | :sl:`set smoothscale filter version to one of: 'GENERIC', 'MMX', or 'SSE'` + | :sg:`set_smoothscale_backend(backend) -> None` + + Sets smoothscale acceleration. Takes a string argument. A value of 'GENERIC' + turns off acceleration. 'MMX' uses ``MMX`` instructions only. 'SSE' allows + ``SSE`` extensions as well. A value error is raised if type is not + recognized or not supported by the current processor. + + This function is provided for pygame testing and debugging. If smoothscale + causes an invalid instruction error then it is a pygame/SDL bug that should + be reported. Use this function as a temporary fix only. + + .. ## pygame.transform.set_smoothscale_backend ## + +.. function:: chop + + | :sl:`gets a copy of an image with an interior area removed` + | :sg:`chop(surface, rect) -> Surface` + + Extracts a portion of an image. All vertical and horizontal pixels + surrounding the given rectangle area are removed. The corner areas (diagonal + to the rect) are then brought together. (The original image is not altered + by this operation.) + + ``NOTE``: If you want a "crop" that returns the part of an image within a + rect, you can blit with a rect to a new surface or copy a subsurface. + + .. ## pygame.transform.chop ## + +.. function:: laplacian + + | :sl:`find edges in a surface` + | :sg:`laplacian(surface, dest_surface=None) -> Surface` + + Finds the edges in a surface using the laplacian algorithm. + + .. versionadded:: 1.8 + + .. ## pygame.transform.laplacian ## + +.. function:: average_surfaces + + | :sl:`find the average surface from many surfaces.` + | :sg:`average_surfaces(surfaces, dest_surface=None, palette_colors=1) -> Surface` + + Takes a sequence of surfaces and returns a surface with average colors from + each of the surfaces. + + palette_colors - if true we average the colors in palette, otherwise we + average the pixel values. This is useful if the surface is actually + greyscale colors, and not palette colors. + + Note, this function currently does not handle palette using surfaces + correctly. + + .. versionadded:: 1.8 + .. versionadded:: 1.9 ``palette_colors`` argument + + .. ## pygame.transform.average_surfaces ## + +.. function:: average_color + + | :sl:`finds the average color of a surface` + | :sg:`average_color(surface, rect=None, consider_alpha=False) -> Color` + + Finds the average color of a Surface or a region of a surface specified by a + Rect, and returns it as a Color. If consider_alpha is set to True, then alpha is + taken into account (removing the black artifacts). + + .. versionadded:: 2.1.2 ``consider_alpha`` argument + + .. ## pygame.transform.average_color ## + +.. function:: grayscale + + | :sl:`grayscale a surface` + | :sg:`grayscale(surface, dest_surface=None) -> Surface` + + Returns a grayscaled version of the original surface using the luminosity formula which weights red, green and blue according to their wavelengths. + + An optional destination surface can be passed which is faster than creating a new Surface. + This destination surface must have the same dimensions (width, height) and depth as the source Surface. + + .. ## pygame.transform.grayscale ## + +.. function:: threshold + + | :sl:`finds which, and how many pixels in a surface are within a threshold of a 'search_color' or a 'search_surf'.` + | :sg:`threshold(dest_surface, surface, search_color, threshold=(0,0,0,0), set_color=(0,0,0,0), set_behavior=1, search_surf=None, inverse_set=False) -> num_threshold_pixels` + + This versatile function can be used for find colors in a 'surf' close to a 'search_color' + or close to colors in a separate 'search_surf'. + + It can also be used to transfer pixels into a 'dest_surf' that match or don't match. + + By default it sets pixels in the 'dest_surf' where all of the pixels NOT within the + threshold are changed to set_color. If inverse_set is optionally set to True, + the pixels that ARE within the threshold are changed to set_color. + + If the optional 'search_surf' surface is given, it is used to threshold against + rather than the specified 'set_color'. That is, it will find each pixel in the + 'surf' that is within the 'threshold' of the pixel at the same coordinates + of the 'search_surf'. + + :param dest_surf: Surface we are changing. See 'set_behavior'. + Should be None if counting (set_behavior is 0). + :type dest_surf: pygame.Surface or None + + :param pygame.Surface surf: Surface we are looking at. + + :param pygame.Color search_color: Color we are searching for. + + :param pygame.Color threshold: Within this distance from search_color (or search_surf). + You can use a threshold of (r,g,b,a) where the r,g,b can have different + thresholds. So you could use an r threshold of 40 and a blue threshold of 2 + if you like. + + :param set_color: Color we set in dest_surf. + :type set_color: pygame.Color or None + + :param int set_behavior: + - set_behavior=1 (default). Pixels in dest_surface will be changed to 'set_color'. + - set_behavior=0 we do not change 'dest_surf', just count. Make dest_surf=None. + - set_behavior=2 pixels set in 'dest_surf' will be from 'surf'. + + :param search_surf: + - search_surf=None (default). Search against 'search_color' instead. + - search_surf=Surface. Look at the color in 'search_surf' rather than using 'search_color'. + :type search_surf: pygame.Surface or None + + :param bool inverse_set: + - False, default. Pixels outside of threshold are changed. + - True, Pixels within threshold are changed. + + :rtype: int + :returns: The number of pixels that are within the 'threshold' in 'surf' + compared to either 'search_color' or `search_surf`. + + :Examples: + + See the threshold tests for a full of examples: https://github.com/pygame/pygame/blob/main/test/transform_test.py + + .. literalinclude:: ../../../test/transform_test.py + :pyobject: TransformModuleTest.test_threshold_dest_surf_not_change + + + .. versionadded:: 1.8 + .. versionchanged:: 1.9.4 + Fixed a lot of bugs and added keyword arguments. Test your code. + + .. ## pygame.transform.threshold ## + +.. ## pygame.transform ## diff --git a/docs/tut/CameraIntro.rst b/docs/tut/CameraIntro.rst new file mode 100644 index 0000000..9f99c55 --- /dev/null +++ b/docs/tut/CameraIntro.rst @@ -0,0 +1,299 @@ +.. TUTORIAL:Camera Module Introduction + +.. include:: common.txt + +************************************************* + Pygame Tutorials - Camera Module Introduction +************************************************* + + +Camera Module Introduction +========================== + +.. rst-class:: docinfo + +:Author: by Nirav Patel +:Contact: nrp@eclecti.cc + + +Pygame 1.9 comes with support for interfacing cameras, allowing you to capture +still images, watch live streams, and do some simple computer vision. This +tutorial will cover all of those use cases, providing code samples you can base +your app or game on. You can refer to the :mod:`reference documentation ` +for the full API. + +.. note:: + + As of Pygame 1.9, the camera module offers native support for cameras + that use v4l2 on Linux. There is support for other platforms via Videocapture + or OpenCV, but this guide will focus on the native module. Most of the code + will be valid for other platforms, but certain things like controls will not + work. The module is also marked as **EXPERIMENTAL**, meaning the API could + change in subsequent versions. + + +Import and Init +--------------- + +:: + + import pygame + import pygame.camera + from pygame.locals import * + + pygame.init() + pygame.camera.init() + +As the camera module is optional, it needs to be imported and initialized +manually as shown above. + + +Capturing a Single Image +------------------------ + +Now we will go over the simplest case of opening a camera and capturing a frame +as a surface. In the below example, we assume that there is a camera at +/dev/video0 on the computer, and initialize it with a size of 640 by 480. +The surface called image is whatever the camera was seeing when get_image() was +called. :: + + cam = pygame.camera.Camera("/dev/video0",(640,480)) + cam.start() + image = cam.get_image() + + +Listing Connected Cameras +^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may be wondering, what if we don't know the exact path of the camera? +We can ask the module to provide a list of cameras attached to the +computer and initialize the first camera in the list. :: + + camlist = pygame.camera.list_cameras() + if camlist: + cam = pygame.camera.Camera(camlist[0],(640,480)) + + +Using Camera Controls +^^^^^^^^^^^^^^^^^^^^^ + +Most cameras support controls like flipping the image and changing brightness. +set_controls() and get_controls() can be used at any point after using start(). :: + + cam.set_controls(hflip = True, vflip = False) + print camera.get_controls() + + +Capturing a Live Stream +----------------------- + +The rest of this tutorial will be based around capturing a live stream of +images. For this, we will be using the class below. As described, it will +simply blit a constant stream of camera frames to the screen, effectively +showing live video. It is basically what you would expect, looping get_image(), +blitting to the display surface, and flipping it. For performance reasons, +we will be supplying the camera with the same surface to use each time. :: + + class Capture: + def __init__(self): + self.size = (640,480) + # create a display surface. standard pygame stuff + self.display = pygame.display.set_mode(self.size, 0) + + # this is the same as what we saw before + self.clist = pygame.camera.list_cameras() + if not self.clist: + raise ValueError("Sorry, no cameras detected.") + self.cam = pygame.camera.Camera(self.clist[0], self.size) + self.cam.start() + + # create a surface to capture to. for performance purposes + # bit depth is the same as that of the display surface. + self.snapshot = pygame.surface.Surface(self.size, 0, self.display) + + def get_and_flip(self): + # if you don't want to tie the framerate to the camera, you can check + # if the camera has an image ready. note that while this works + # on most cameras, some will never return true. + if self.cam.query_image(): + self.snapshot = self.cam.get_image(self.snapshot) + + # blit it to the display surface. simple! + self.display.blit(self.snapshot, (0,0)) + pygame.display.flip() + + def main(self): + going = True + while going: + events = pygame.event.get() + for e in events: + if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE): + # close the camera safely + self.cam.stop() + going = False + + self.get_and_flip() + + +Since get_image() is a blocking call that could take quite a bit of time on a +slow camera, this example uses query_image() to see if the camera is ready. +This allows you to separate the framerate of your game from that of your camera. +It is also possible to have the camera capturing images in a separate thread, +for approximately the same performance gain, if you find that your camera does +not support the query_image() function correctly. + + +Basic Computer Vision +--------------------- + +By using the camera, transform, and mask modules, pygame can do some basic +computer vision. + + +Colorspaces +^^^^^^^^^^^ + +When initializing a camera, colorspace is an optional parameter, with 'RGB', +'YUV', and 'HSV' as the possible choices. YUV and HSV are both generally more +useful for computer vision than RGB, and allow you to more easily threshold by +color, something we will look at later in the tutorial. + +:: + + self.cam = pygame.camera.Camera(self.clist[0], self.size, "RGB") + +.. image:: camera_rgb.jpg + :class: trailing + +:: + + self.cam = pygame.camera.Camera(self.clist[0], self.size, "YUV") + +.. image:: camera_yuv.jpg + :class: trailing + +:: + + self.cam = pygame.camera.Camera(self.clist[0], self.size, "HSV") + +.. image:: camera_hsv.jpg + :class: trailing + + +Thresholding +^^^^^^^^^^^^ + +Using the threshold() function from the transform module, one can do simple +green screen like effects, or isolate specifically colored objects in a scene. +In the below example, we threshold out just the green tree and make the rest +of the image black. Check the reference documentation for details on the +:func:`threshold function `\ . + +:: + + self.thresholded = pygame.surface.Surface(self.size, 0, self.display) + self.snapshot = self.cam.get_image(self.snapshot) + pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(90,170,170),(0,0,0),2) + +.. image:: camera_thresholded.jpg + :class: trailing + + +Of course, this is only useful if you already know the exact color of the object +you are looking for. To get around this and make thresholding usable in the +real world, we need to add a calibration stage where we identify the color of an +object and use it to threshold against. We will be using the average_color() +function of the transform module to do this. Below is an example calibration +function that you could loop until an event like a key press, and an image of +what it would look like. The color inside the box will be the one that is +used for the threshold. Note that we are using the HSV colorspace in the below +images. + +:: + + def calibrate(self): + # capture the image + self.snapshot = self.cam.get_image(self.snapshot) + # blit it to the display surface + self.display.blit(self.snapshot, (0,0)) + # make a rect in the middle of the screen + crect = pygame.draw.rect(self.display, (255,0,0), (145,105,30,30), 4) + # get the average color of the area inside the rect + self.ccolor = pygame.transform.average_color(self.snapshot, crect) + # fill the upper left corner with that color + self.display.fill(self.ccolor, (0,0,50,50)) + pygame.display.flip() + +.. image:: camera_average.jpg + :class: trailing + +:: + + pygame.transform.threshold(self.thresholded,self.snapshot,self.ccolor,(30,30,30),(0,0,0),2) + +.. image:: camera_thresh.jpg + :class: trailing + + +You can use the same idea to do a simple green screen/blue screen, by first +getting a background image and then thresholding against it. The below example +just has the camera pointed at a blank white wall in HSV colorspace. + +:: + + def calibrate(self): + # capture a bunch of background images + bg = [] + for i in range(0,5): + bg.append(self.cam.get_image(self.background)) + # average them down to one to get rid of some noise + pygame.transform.average_surfaces(bg,self.background) + # blit it to the display surface + self.display.blit(self.background, (0,0)) + pygame.display.flip() + +.. image:: camera_background.jpg + :class: trailing + +:: + + pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(30,30,30),(0,0,0),1,self.background) + +.. image:: camera_green.jpg + :class: trailing + + +Using the Mask Module +^^^^^^^^^^^^^^^^^^^^^ + +The stuff above is great if you just want to display images, but with the +:mod:`mask module `, you can also use a camera as an +input device for a game. For example, going back to the example of +thresholding out a specific object, we can find the position of that object and +use it to control an on screen object. + +:: + + def get_and_flip(self): + self.snapshot = self.cam.get_image(self.snapshot) + # threshold against the color we got before + mask = pygame.mask.from_threshold(self.snapshot, self.ccolor, (30, 30, 30)) + self.display.blit(self.snapshot,(0,0)) + # keep only the largest blob of that color + connected = mask.connected_component() + # make sure the blob is big enough that it isn't just noise + if mask.count() > 100: + # find the center of the blob + coord = mask.centroid() + # draw a circle with size variable on the size of the blob + pygame.draw.circle(self.display, (0,255,0), coord, max(min(50,mask.count()/400),5)) + pygame.display.flip() + +.. image:: camera_mask.jpg + :class: trailing + + +This is just the most basic example. You can track multiple different colored +blobs, find the outlines of objects, have collision detection between real life +and in game objects, get the angle of an object to allow for even finer control, +and more. Have fun! diff --git a/docs/tut/ChimpLineByLine.rst b/docs/tut/ChimpLineByLine.rst new file mode 100644 index 0000000..bb7a0f6 --- /dev/null +++ b/docs/tut/ChimpLineByLine.rst @@ -0,0 +1,541 @@ +.. TUTORIAL:Line by Line Descriptions of the Chimp Example + +.. include:: common.txt + +************************************************* + Pygame Tutorials - Line By Line Chimp Example +************************************************* + + +Line By Line Chimp +================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + +.. toctree:: + :hidden: + + chimp.py + + +Introduction +------------ + +In the *pygame* examples there is a simple example named "chimp". +This example simulates a punchable monkey moving around the screen with +promises of riches and reward. The example itself is very simple, and a +bit thin on error-checking code. This example program demonstrates many of +pygame's abilities, like creating a window, loading images and sounds, +rendering text, and basic event and mouse handling. + +The program and images can be found inside the standard source distribution +of pygame. You can run it by running `python -m pygame.examples.chimp` in +your terminal. + +This tutorial will go through the code block by block. Explaining how +the code works. There will also be mention of how the code could be improved +and what error checking could help out. + +This is an excellent tutorial for people getting their first look at +the *pygame* code. Once *pygame* is fully installed, you can find +and run the chimp demo for yourself in the examples directory. + +.. container:: fullwidth leading trailing + + .. rst-class:: small-heading + + (no, this is not a banner ad, it's the screenshot) + + .. image:: chimpshot.gif + :alt: chimp game banner + + :doc:`Full Source ` + + +Import Modules +-------------- + +This is the code that imports all the needed modules into your program. +It also checks for the availability of some of the optional pygame modules. :: + + # Import Modules + import os + import pygame as pg + + if not pg.font: + print("Warning, fonts disabled") + if not pg.mixer: + print("Warning, sound disabled") + + main_dir = os.path.split(os.path.abspath(__file__))[0] + data_dir = os.path.join(main_dir, "data") + + +First, we import the standard "os" python module. This allow +us to do things like create platform independent file paths. + +In the next line, we import the pygame package. In our case, we import +pygame as ``pg``, so that all of the functionality of pygame is able to +be referenced from the namespace ``pg``. + +Some pygame modules are optional, and if they aren't found, +they evaluate to ``False``. Because of that, we decide to print +a nice warning message if the :mod:`font` or +:mod:`mixer ` modules in pygame are not available. +(Although they will only be unavailable in very uncommon situations). + +Lastly, we prepare two paths for the rest of the code to use. +``main_dir`` uses the `os.path` module and the `__file__` variable provided +by Python to locate the game's python file, and extract the folder from +that path. It then prepares the variable ``data_dir`` to tell the +loading functions exactly where to look. + + +Loading Resources +----------------- + +Here we have two functions we can use to load images and sounds. We will +look at each function individually in this section. :: + + def load_image(name, colorkey=None, scale=1): + fullname = os.path.join(data_dir, name) + image = pg.image.load(fullname) + + size = image.get_size() + size = (size[0] * scale, size[1] * scale) + image = pg.transform.scale(image, size) + + image = image.convert() + if colorkey is not None: + if colorkey == -1: + colorkey = image.get_at((0, 0)) + image.set_colorkey(colorkey, pg.RLEACCEL) + return image, image.get_rect() + + +This function takes the name of an image to load. It also optionally +takes an argument it can use to set a colorkey for the image, and an argument +to scale the image. A colorkey is used in graphics to represent a color of the +image that is transparent. + +The first thing this function does is create a full pathname to the file. +In this example all the resources are in a "data" subdirectory. By using +the `os.path.join` function, a pathname will be created that works for whatever +platform the game is running on. + +Next we load the image using the :func:`pygame.image.load` function. +After the image is loaded, we make an important +call to the `convert()` function. This makes a new copy of a Surface and converts +its color format and depth to match the display. This means blitting the +image to the screen will happen as quickly as possible. + +We then scale the image, using the :func:`pygame.transform.scale` function. +This function takes a Surface and the size it should be scaled to. To scale +by a scalar, we can get the size and scale the x and y by the scalar. + +Last, we set the colorkey for the image. If the user supplied an argument +for the colorkey argument we use that value as the colorkey for the image. +This would usually just be a color RGB value, like (255, 255, 255) for +white. You can also pass a value of -1 as the colorkey. In this case the +function will lookup the color at the topleft pixel of the image, and use +that color for the colorkey. :: + + def load_sound(name): + class NoneSound: + def play(self): + pass + + if not pg.mixer or not pg.mixer.get_init(): + return NoneSound() + + fullname = os.path.join(data_dir, name) + sound = pg.mixer.Sound(fullname) + + return sound + + +Next is the function to load a sound file. The first thing this function +does is check to see if the :mod:`pygame.mixer` module was imported correctly. +If not, it returns a small class instance that has a dummy play method. +This will act enough like a normal Sound object for this game to run without +any extra error checking. + +This function is similar to the image loading function, but handles some +different problems. First we create a full path to the sound image, and +load the sound file. Then we simply return the loaded Sound object. + + +Game Object Classes +------------------- + +Here we create two classes to represent the objects in our game. Almost +all the logic for the game goes into these two classes. We will look over +them one at a time here. :: + + class Fist(pg.sprite.Sprite): + """moves a clenched fist on the screen, following the mouse""" + + def __init__(self): + pg.sprite.Sprite.__init__(self) # call Sprite initializer + self.image, self.rect = load_image("fist.png", -1) + self.fist_offset = (-235, -80) + self.punching = False + + def update(self): + """move the fist based on the mouse position""" + pos = pg.mouse.get_pos() + self.rect.topleft = pos + self.rect.move_ip(self.fist_offset) + if self.punching: + self.rect.move_ip(15, 25) + + def punch(self, target): + """returns true if the fist collides with the target""" + if not self.punching: + self.punching = True + hitbox = self.rect.inflate(-5, -5) + return hitbox.colliderect(target.rect) + + def unpunch(self): + """called to pull the fist back""" + self.punching = False + + +Here we create a class to represent the players fist. It is derived from +the `Sprite` class included in the :mod:`pygame.sprite` module. The `__init__` function +is called when new instances of this class are created. The first thing +we do is be sure to call the `__init__` function for our base class. This +allows the Sprite's `__init__` function to prepare our object for use as a +sprite. This game uses one of the sprite drawing Group classes. These classes +can draw sprites that have an "image" and "rect" attribute. By simply changing +these two attributes, the renderer will draw the current image at the current +position. + +All sprites have an `update()` method. This function is typically called +once per frame. It is where you should put code that moves and updates +the variables for the sprite. The `update()` method for the fist moves the +fist to the location of the mouse pointer. It also offsets the fist position +slightly if the fist is in the "punching" state. + +The following two functions `punch()` and `unpunch()` change the punching +state for the fist. The `punch()` method also returns a true value if the fist +is colliding with the given target sprite. :: + + class Chimp(pg.sprite.Sprite): + """moves a monkey critter across the screen. it can spin the + monkey when it is punched.""" + + def __init__(self): + pg.sprite.Sprite.__init__(self) # call Sprite initializer + self.image, self.rect = load_image("chimp.png", -1, 4) + screen = pg.display.get_surface() + self.area = screen.get_rect() + self.rect.topleft = 10, 90 + self.move = 18 + self.dizzy = False + + def update(self): + """walk or spin, depending on the monkeys state""" + if self.dizzy: + self._spin() + else: + self._walk() + + def _walk(self): + """move the monkey across the screen, and turn at the ends""" + newpos = self.rect.move((self.move, 0)) + if not self.area.contains(newpos): + if self.rect.left < self.area.left or self.rect.right > self.area.right: + self.move = -self.move + newpos = self.rect.move((self.move, 0)) + self.image = pg.transform.flip(self.image, True, False) + self.rect = newpos + + def _spin(self): + """spin the monkey image""" + center = self.rect.center + self.dizzy = self.dizzy + 12 + if self.dizzy >= 360: + self.dizzy = False + self.image = self.original + else: + rotate = pg.transform.rotate + self.image = rotate(self.original, self.dizzy) + self.rect = self.image.get_rect(center=center) + + def punched(self): + """this will cause the monkey to start spinning""" + if not self.dizzy: + self.dizzy = True + self.original = self.image + + +The `Chimp` class is doing a little more work than the fist, but nothing +more complex. This class will move the chimp back and forth across the +screen. When the monkey is punched, he will spin around to exciting effect. +This class is also derived from the base :class:`Sprite ` +class, and is initialized the same as the fist. While initializing, the class +also sets the attribute "area" to be the size of the display screen. + +The `update` function for the chimp simply looks at the current "dizzy" +state, which is true when the monkey is spinning from a punch. It calls either +the `_spin` or `_walk` method. These functions are prefixed with an underscore. +This is just a standard python idiom which suggests these methods should +only be used by the `Chimp` class. We could go so far as to give them a double +underscore, which would tell python to really try to make them private +methods, but we don't need such protection. :) + +The `_walk` method creates a new position for the monkey by moving the current +rect by a given offset. If this new position crosses outside the display +area of the screen, it reverses the movement offset. It also mirrors the +image using the :func:`pygame.transform.flip` function. This is a crude effect +that makes the monkey look like he's turning the direction he is moving. + +The `_spin` method is called when the monkey is currently "dizzy". The dizzy +attribute is used to store the current amount of rotation. When the monkey +has rotated all the way around (360 degrees) it resets the monkey image +back to the original, non-rotated version. Before calling the +:func:`pygame.transform.rotate` function, you'll see the code makes a local +reference to the function simply named "rotate". There is no need to do that +for this example, it is just done here to keep the following line's length a +little shorter. Note that when calling the `rotate` function, we are always +rotating from the original monkey image. When rotating, there is a slight loss +of quality. Repeatedly rotating the same image and the quality would get worse +each time. Also, when rotating an image, the size of the image will actually +change. This is because the corners of the image will be rotated out, making +the image bigger. We make sure the center of the new image matches the center +of the old image, so it rotates without moving. + +The last method is `punched()` which tells the sprite to enter its dizzy +state. This will cause the image to start spinning. It also makes a copy +of the current image named "original". + + +Initialize Everything +--------------------- + +Before we can do much with pygame, we need to make sure its modules +are initialized. In this case we will also open a simple graphics window. +Now we are in the `main()` function of the program, which actually runs everything. :: + + pg.init() + screen = pg.display.set_mode((1280, 480), pg.SCALED) + pg.display.set_caption("Monkey Fever") + pg.mouse.set_visible(False) + +The first line to initialize *pygame* takes care of a bit of +work for us. It checks through the imported *pygame* modules and attempts +to initialize each one of them. It is possible to go back and check if modules +failed to initialize, but we won't bother here. It is also possible to +take a lot more control and initialize each specific module by hand. That +type of control is generally not needed, but is available if you desire. + +Next we set up the display graphics mode. Note that the :mod:`pygame.display` +module is used to control all the display settings. In this case we are +asking for a 1280 by 480 window, with the ``SCALED`` display flag. +This automatically scales up the window for displays much larger than the +window. + +Last we set the window title and turn off the mouse cursor for our +window. Very basic to do, and now we have a small black window ready to +do our bidding. Usually the cursor defaults to visible, so there is no need +to really set the state unless we want to hide it. + + +Create The Background +--------------------- + +Our program is going to have text message in the background. It would +be nice for us to create a single surface to represent the background and +repeatedly use that. The first step is to create the surface. :: + + background = pg.Surface(screen.get_size()) + background = background.convert() + background.fill((170, 238, 187)) + +This creates a new surface for us that is the same size as the display +window. Note the extra call to `convert()` after creating the Surface. The +convert with no arguments will make sure our background is the same format +as the display window, which will give us the fastest results. + +We also fill the entire background with a certain green color. The fill() +function usually takes an RGB triplet as arguments, but supports many +input formats. See the :mod:`pygame.Color` for all the color formats. + + +Put Text On The Background, Centered +------------------------------------ + +Now that we have a background surface, lets get the text rendered to it. We +only do this if we see the :mod:`pygame.font` module has imported properly. +If not, we just skip this section. :: + + if pg.font: + font = pg.font.Font(None, 64) + text = font.render("Pummel The Chimp, And Win $$$", True, (10, 10, 10)) + textpos = text.get_rect(centerx=background.get_width() / 2, y=10) + background.blit(text, textpos) + +As you see, there are a couple steps to getting this done. First we +must create the font object and render it into a new surface. We then find +the center of that new surface and blit (paste) it onto the background. + +The font is created with the `font` module's `Font()` constructor. Usually +you will pass the name of a TrueType font file to this function, but we +can also pass `None`, which will use a default font. The `Font` constructor +also needs to know the size of font we want to create. + +We then render that font into a new surface. The `render` function creates +a new surface that is the appropriate size for our text. In this case +we are also telling render to create antialiased text (for a nice smooth +look) and to use a dark grey color. + +Next we need to find the centered position of the text on our display. +We create a "Rect" object from the text dimensions, which allows us to +easily assign it to the screen center. + +Finally we blit (blit is like a copy or paste) the text onto the background +image. + + +Display The Background While Setup Finishes +------------------------------------------- + +We still have a black window on the screen. Lets show our background +while we wait for the other resources to load. :: + + screen.blit(background, (0, 0)) + pg.display.flip() + +This will blit our entire background onto the display window. The +blit is self explanatory, but what about this flip routine? + +In pygame, changes to the display surface are not immediately visible. +Normally, a display must be updated in areas that have changed for them +to be visible to the user. In this case the `flip()` function works nicely +because it simply handles the entire window area. + + +Prepare Game Object +------------------- + +Here we create all the objects that the game is going to need. + +:: + + whiff_sound = load_sound("whiff.wav") + punch_sound = load_sound("punch.wav") + chimp = Chimp() + fist = Fist() + allsprites = pg.sprite.RenderPlain((chimp, fist)) + clock = pg.time.Clock() + +First we load two sound effects using the `load_sound` function we defined +above. Then we create an instance of each of our sprite classes. And lastly +we create a sprite :class:`Group ` which will contain all +our sprites. + +We actually use a special sprite group named :class:`RenderPlain +`. This sprite group can draw all the sprites it +contains to the screen. It is called `RenderPlain` because there are actually +more advanced Render groups. But for our game, we just need simple drawing. We +create the group named "allsprites" by passing a list with all the sprites that +should belong in the group. We could later on add or remove sprites from this +group, but in this game we won't need to. + +The `clock` object we create will be used to help control our game's framerate. +we will use it in the main loop of our game to make sure it doesn't run too fast. + + +Main Loop +--------- + +Nothing much here, just an infinite loop. :: + + going = True + while going: + clock.tick(60) + +All games run in some sort of loop. The usual order of things is to +check on the state of the computer and user input, move and update the +state of all the objects, and then draw them to the screen. You'll see +that this example is no different. + +We also make a call to our `clock` object, which will make sure our game +doesn't run faster than 60 frames per second. + + +Handle All Input Events +----------------------- + +This is an extremely simple case of working the event queue. :: + + for event in pg.event.get(): + if event.type == pg.QUIT: + going = False + elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE: + going = False + elif event.type == pg.MOUSEBUTTONDOWN: + if fist.punch(chimp): + punch_sound.play() # punch + chimp.punched() + else: + whiff_sound.play() # miss + elif event.type == pg.MOUSEBUTTONUP: + fist.unpunch() + +First we get all the available Events from pygame and loop through each +of them. The first two tests see if the user has quit our game, or pressed +the escape key. In these cases we just set ``going`` to ``False``, allowing +us out of the infinite loop. + +Next we just check to see if the mouse button was pressed or released. +If the button was pressed, we ask the fist object if it has collided with +the chimp. We play the appropriate sound effect, and if the monkey was hit, +we tell him to start spinning (by calling his `punched()` method). + + +Update the Sprites +------------------ + +:: + + allsprites.update() + +Sprite groups have an `update()` method, which simply calls the update method +for all the sprites it contains. Each of the objects will move around, depending +on which state they are in. This is where the chimp will move one step side +to side, or spin a little farther if he was recently punched. + + +Draw The Entire Scene +--------------------- + +Now that all the objects are in the right place, time to draw them. :: + + screen.blit(background, (0, 0)) + allsprites.draw(screen) + pg.display.flip() + +The first blit call will draw the background onto the entire screen. This +erases everything we saw from the previous frame (slightly inefficient, but +good enough for this game). Next we call the `draw()` method of the sprite +container. Since this sprite container is really an instance of the "RenderPlain" +sprite group, it knows how to draw our sprites. Lastly, we `flip()` the contents +of pygame's software double buffer to the screen. This makes everything we've +drawn visible all at once. + + +Game Over +--------- + +User has quit, time to clean up. :: + + pg.quit() + +Cleaning up the running game in *pygame* is extremely simple. +Since all variables are automatically destructed, we don't really have to do +anything, but calling `pg.quit()` explicitly cleans up pygame's internals. diff --git a/docs/tut/DisplayModes.rst b/docs/tut/DisplayModes.rst new file mode 100644 index 0000000..c251898 --- /dev/null +++ b/docs/tut/DisplayModes.rst @@ -0,0 +1,197 @@ +.. TUTORIAL: Choosing and Configuring Display Modes + +.. include:: common.txt + +******************************************** + Pygame Tutorials - Setting Display Modes +******************************************** + + +Setting Display Modes +===================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + + +Introduction +------------ + +Setting the display mode in *pygame* creates a visible image surface +on the monitor. +This surface can either cover the full screen, or be windowed +on platforms that support a window manager. +The display surface is nothing more than a standard *pygame* surface object. +There are special functions needed in the :mod:`pygame.display` +module to keep the image surface contents updated on the monitor. + +Setting the display mode in *pygame* is an easier task than with most +graphic libraries. +The advantage is if your display mode is not available, +*pygame* will emulate the display mode that you asked for. +*Pygame* will select a display resolution and color depth that best matches +the settings you have requested, +then allow you to access the display with the format you have requested. +In reality, since the :mod:`pygame.display` module is +a binding around the SDL library, SDL is really doing all this work. + +There are advantages and disadvantages to setting the display mode in this +manner. +The advantage is that if your game requires a specific display mode, +your game will run on platforms that do not support your requirements. +It also makes life easier when you're getting something started, +it is always easy to go back later and make the mode selection a little more +particular. +The disadvantage is that what you request is not always what you will get. +There is also a performance penalty when the display mode must be emulated. +This tutorial will help you understand the different methods for querying +the platforms display capabilities, and setting the display mode for your game. + + +Setting Basics +-------------- + +The first thing to learn about is how to actually set the current display mode. +The display mode may be set at any time after the :mod:`pygame.display` +module has been initialized. +If you have previously set the display mode, +setting it again will change the current mode. +Setting the display mode is handled with the function +:func:`pygame.display.set_mode((width, height), flags, depth) +`. +The only required argument in this function is a sequence containing +the width and height of the new display mode. +The depth flag is the requested bits per pixel for the surface. +If the given depth is 8, *pygame* will create a color-mapped surface. +When given a higher bit depth, *pygame* will use a packed color mode. +Much more information about depths and color modes can be found in the +documentation for the display and surface modules. +The default value for depth is 0. +When given an argument of 0, *pygame* will select the best bit depth to use, +usually the same as the system's current bit depth. +The flags argument lets you control extra features for the display mode. +Again, more information about this is found in the *pygame* reference documents. + + +How to Decide +------------- + +So how do you select a display mode that is going to work best with your +graphic resources and the platform your game is running on? +There are several methods for gathering information about the display device. +All of these methods must be called after the display module has been +initialized, but you likely want to call them before setting the display mode. +First, :func:`pygame.display.Info() ` +will return a special object type of VidInfo, +which can tell you a lot about the graphics driver capabilities. +The function +:func:`pygame.display.list_modes(depth, flags) ` +can be used to find the supported graphic modes by the system. +:func:`pygame.display.mode_ok((width, height), flags, depth) +` takes the same arguments as +:func:`set_mode() `, +but returns the closest matching bit depth to the one you request. +Lastly, :func:`pygame.display.get_driver() ` +will return the name of the graphics driver selected by *pygame*. + +Just remember the golden rule. +*Pygame* will work with pretty much any display mode you request. +Some display modes will need to be emulated, +which will slow your game down, +since *pygame* will need to convert every update you make to the +"real" display mode. The best bet is to always let *pygame* +choose the best bit depth, +and convert all your graphic resources to that format when they are loaded. +You let *pygame* choose its bit depth by calling +:func:`set_mode() ` +with no depth argument or a depth of 0, +or you can call +:func:`mode_ok() ` +to find a closest matching bit depth to what you need. + +When your display mode is windowed, +you usually must match the same bit depth as the desktop. +When you are fullscreen, some platforms can switch to any bit depth that +best suits your needs. +You can find the depth of the current desktop if you get a VidInfo object +before ever setting your display mode. + +After setting the display mode, +you can find out information about its settings by getting a VidInfo object, +or by calling any of the Surface.get* methods on the display surface. + + +Functions +--------- + +These are the routines you can use to determine the most appropriate +display mode. +You can find more information about these functions in the display module +documentation. + + :func:`pygame.display.mode_ok(size, flags, depth) ` + + This function takes the exact same arguments as pygame.display.set_mode(). + It returns the best available bit depth for the mode you have described. + If this returns zero, + then the desired display mode is not available without emulation. + + :func:`pygame.display.list_modes(depth, flags) ` + + Returns a list of supported display modes with the requested + depth and flags. + An empty list is returned when there are no modes. + The flags argument defaults to :any:`FULLSCREEN `\ . + If you specify your own flags without :any:`FULLSCREEN `\ , + you will likely get a return value of -1. + This means that any display size is fine, since the display will be windowed. + Note that the listed modes are sorted largest to smallest. + + :func:`pygame.display.Info() ` + + This function returns an object with many members describing + the display device. + Printing the VidInfo object will quickly show you all the + members and values for this object. :: + + >>> import pygame.display + >>> pygame.display.init() + >>> info = pygame.display.Info() + >>> print(info) + + +You can test all these flags as simply members of the VidInfo object. + + +Examples +-------- + +Here are some examples of different methods to init the graphics display. +They should help you get an idea of how to go about setting your display mode. :: + + >>> # give me the best depth with a 640 x 480 windowed display + >>> pygame.display.set_mode((640, 480)) + + >>> # give me the biggest 16-bit display available + >>> modes = pygame.display.list_modes(16) + >>> if not modes: + ... print('16-bit not supported') + ... else: + ... print('Found Resolution:', modes[0]) + ... pygame.display.set_mode(modes[0], FULLSCREEN, 16) + + >>> # need an 8-bit surface, nothing else will do + >>> if pygame.display.mode_ok((800, 600), 0, 8) != 8: + ... print('Can only work with an 8-bit display, sorry') + ... else: + ... pygame.display.set_mode((800, 600), 0, 8) diff --git a/docs/tut/ImportInit.rst b/docs/tut/ImportInit.rst new file mode 100644 index 0000000..1077126 --- /dev/null +++ b/docs/tut/ImportInit.rst @@ -0,0 +1,76 @@ +.. TUTORIAL:Import and Initialize + +.. include:: common.txt + +******************************************** + Pygame Tutorials - Import and Initialize +******************************************** + +Import and Initialize +===================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + + +Getting pygame imported and initialized is a very simple process. It is also +flexible enough to give you control over what is happening. Pygame is a +collection of different modules in a single python package. Some of the +modules are written in C, and some are written in python. Some modules +are also optional, and might not always be present. + +This is just a quick introduction on what is going on when you import pygame. +For a clearer explanation definitely see the pygame examples. + + +Import +------ + +First we must import the pygame package. Since pygame version 1.4 this +has been updated to be much easier. Most games will import all of pygame like this. :: + + import pygame + from pygame.locals import * + +The first line here is the only necessary one. It imports all the available pygame +modules into the pygame package. The second line is optional, and puts a limited +set of constants and functions into the global namespace of your script. + +An important thing to keep in mind is that several pygame modules are optional. +For example, one of these is the font module. When you "import pygame", pygame +will check to see if the font module is available. If the font module is available +it will be imported as "pygame.font". If the module is not available, "pygame.font" +will be set to None. This makes it fairly easy to later on test if the font module is available. + + +Init +---- + +Before you can do much with pygame, you will need to initialize it. The most common +way to do this is just make one call. :: + + pygame.init() + +This will attempt to initialize all the pygame modules for you. Not all pygame modules +need to be initialized, but this will automatically initialize the ones that do. You can +also easily initialize each pygame module by hand. For example to only initialize the +font module you would just call. :: + + pygame.font.init() + +Note that if there is an error when you initialize with "pygame.init()", it will silently fail. +When hand initializing modules like this, any errors will raise an exception. Any +modules that must be initialized also have a "get_init()" function, which will return true +if the module has been initialized. + +It is safe to call the init() function for any module more than once. + + +Quit +---- + +Modules that are initialized also usually have a quit() function that will clean up. +There is no need to explicitly call these, as pygame will cleanly quit all the +initialized modules when python finishes. diff --git a/docs/tut/MakeGames.rst b/docs/tut/MakeGames.rst new file mode 100644 index 0000000..31e1d76 --- /dev/null +++ b/docs/tut/MakeGames.rst @@ -0,0 +1,136 @@ +.. TUTORIAL:Tom Chance's Making Games Tutorial + +.. include:: common.txt + +**************************** + Making Games With Pygame +**************************** + + +Making Games With Pygame +======================== + +.. toctree:: + :hidden: + :glob: + + tom_games2 + tom_games3 + tom_games4 + tom_games5 + tom_games6 + +Table of Contents +----------------- + +\1. :ref:`Introduction ` + + \1.1. :ref:`A note on coding styles ` + +\2. :ref:`Revision: Pygame fundamentals ` + + \2.1. :ref:`The basic pygame game ` + + \2.2. :ref:`Basic pygame objects ` + + \2.3. :ref:`Blitting ` + + \2.4. :ref:`The event loop ` + + \2.5. :ref:`Ta-da! ` + +\3. :ref:`Kicking things off ` + + \3.1. :ref:`The first lines, and loading modules ` + + \3.2. :ref:`Resource handling functions ` + +\4. :ref:`Game object classes ` + + \4.1. :ref:`A simple ball class ` + + \4.1.1. :ref:`Diversion 1: Sprites ` + + \4.1.2. :ref:`Diversion 2: Vector physics ` + +\5. :ref:`User-controllable objects ` + + \5.1. :ref:`A simple bat class ` + + \5.1.1. :ref:`Diversion 3: Pygame events ` + +\6. :ref:`Putting it all together ` + + \6.1. :ref:`Let the ball hit sides ` + + \6.2. :ref:`Let the ball hit bats ` + + \6.3. :ref:`The Finished product ` + + +.. _makegames-1: + +1. Introduction +--------------- + +First of all, I will assume you have read the :doc:`Line By Line Chimp ` +tutorial, which introduces the basics of Python and pygame. Give it a read before reading this +tutorial, as I won't bother repeating what that tutorial says (or at least not in as much detail). This tutorial is aimed at those +who understand how to make a ridiculously simple little "game", and who would like to make a relatively simple game like Pong. +It introduces you to some concepts of game design, some simple mathematics to work out ball physics, and some ways to keep your +game easy to maintain and expand. + +All the code in this tutorial works toward implementing `TomPong `_, +a game I've written. By the end of the tutorial, you should not only have a firmer grasp of pygame, but +you should also understand how TomPong works, and how to make your own version. + +Now, for a brief recap of the basics of pygame. A common method of organising the code for a game is to divide it into the following +six sections: + + - **Load modules** which are required in the game. Standard stuff, except that you should + remember to import the pygame local names as well as the pygame module itself + + - **Resource handling classes**; define some classes to handle your most basic resources, + which will be loading images and sounds, as well as connecting and disconnecting to and from networks, loading save game + files, and any other resources you might have. + + - **Game object classes**; define the classes for your game object. In the pong example, + these will be one for the player's bat (which you can initialise multiple times, one for each player in the game), and one + for the ball (which can again have multiple instances). If you're going to have a nice in-game menu, it's also a good idea to make a + menu class. + + - **Any other game functions**; define other necessary functions, such as scoreboards, menu + handling, etc. Any code that you could put into the main game logic, but that would make understanding said logic harder, should + be put into its own function. So as plotting a scoreboard isn't game logic, it should be moved into a function. + + - **Initialise the game**, including the pygame objects themselves, the background, the game + objects (initialising instances of the classes) and any other little bits of code you might want to add in. + + - **The main loop**, into which you put any input handling (i.e. watching for users hitting + keys/mouse buttons), the code for updating the game objects, and finally for updating the screen. + +Every game you make will have some or all of those sections, possibly with more of your own. For the purposes of this tutorial, I will +write about how TomPong is laid out, and the ideas I write about can be transferred to almost any kind of game you might make. I will +also assume that you want to keep all of the code in a single file, but if you're making a reasonably large game, it's often a good +idea to source certain sections into module files. Putting the game object classes into a file called ``objects.py``, for +example, can help you keep game logic separate from game objects. If you have a lot of resource handling code, it can also be handy +to put that into ``resources.py``. You can then :code:`from objects,resources import *` to import all of the +classes and functions. + + +.. _makegames-1-1: + +1.1. A note on coding styles +---------------------------- + +The first thing to remember when approaching any programming project is to decide on a coding style, and stay consistent. Python +solves a lot of the problems because of its strict interpretation of whitespace and indentation, but you can still choose the size +of your indentations, whether you put each module import on a new line, how you comment code, etc. You'll see how I do all of this +in the code examples; you needn't use my style, but whatever style you adopt, use it all the way through the program code. Also try +to document all of your classes, and comment on any bits of code that seem obscure, though don't start commenting the obvious. I've +seen plenty of people do the following:: + + player1.score += scoreup # Add scoreup to player1 score + +The worst code is poorly laid out, with seemingly random changes in style, and poor documentation. Poor code is not only annoying +for other people, but it also makes it difficult for you to maintain. diff --git a/docs/tut/MoveIt.rst b/docs/tut/MoveIt.rst new file mode 100644 index 0000000..27fe0f4 --- /dev/null +++ b/docs/tut/MoveIt.rst @@ -0,0 +1,603 @@ +.. TUTORIAL:Help! How Do I Move An Image? + +.. include:: common.txt + +**************************************************** + Pygame Tutorials - Help! How Do I Move An Image? +**************************************************** + +Help! How Do I Move An Image? +============================= + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + + +Many people new to programming and graphics have a hard time figuring +out how to make an image move around the screen. Without understanding +all the concepts, it can be very confusing. You're not the first person +to be stuck here, I'll do my best to take things step by step. We'll even +try to end with methods of keeping your animations efficient. + +Note that we won't be teaching you to program with python in this article, +just introduce you to some of the basics with pygame. + + +Just Pixels On The Screen +------------------------- + +Pygame has a display Surface. This is basically an image that is visible +on the screen, and the image is made up of pixels. The main way you change +these pixels is by calling the blit() function. This copies the pixels +from one image onto another. + +This is the first thing to understand. When you blit an image onto the +screen, you are simply changing the color of the pixels on the screen. +Pixels aren't added or moved, we just change the colors of the pixels already +on the screen. These images you blit to the screen are also Surfaces in +pygame, but they are in no way connected to the display Surface. When they +are blitted to the screen they are copied into the display, but you still +have a unique copy of the original. + +With this brief description. Perhaps you can already understand what +is needed to "move" an image. We don't actually move anything at all. We +simply blit the image in a new position. But before we draw the image in +the new position, we'll need to "erase" the old one. Otherwise the image +will be visible in two places on the screen. By rapidly erasing the image +and redrawing it in a new place, we achieve the "illusion" of movement. + +Through the rest of this tutorial we will break this process down into +simpler steps. Even explaining the best ways to have multiple images moving +around the screen. You probably already have questions. Like, how do we +"erase" the image before drawing it in a new position? Perhaps you're still +totally lost? Well hopefully the rest of this tutorial can straighten things +out for you. + + +Let's Go Back A Step +-------------------- + +Perhaps the concept of pixels and images is still a little foreign to +you? Well good news, for the next few sections we are going to use code that +does everything we want, it just doesn't use pixels. We're going to create +a small python list of 6 numbers, and imagine it represents some fantastic +graphics we could see on the screen. It might actually be surprising how +closely this represents exactly what we'll later be doing with real graphics. + +So let's begin by creating our screen list and fill it with a beautiful +landscape of 1s and 2s. :: + + >>> screen = [1, 1, 2, 2, 2, 1] + >>> print(screen) + [1, 1, 2, 2, 2, 1] + + +Now we've created our background. It's not going to be very exciting +unless we also draw a player on the screen. We'll create a mighty hero +that looks like the number 8. Let's stick him near the middle of the map +and see what it looks like. :: + + >>> screen[3] = 8 + >>> print(screen) + [1, 1, 2, 8, 2, 1] + + +This might have been as far as you've gotten if you jumped right in doing +some graphics programming with pygame. You've got some nice looking stuff +on the screen, but it cannot move anywhere. Perhaps now that our screen +is just a list of numbers, it's easier to see how to move him? + + +Making The Hero Move +-------------------- + +Before we can start moving the character. We need to keep track of some +sort of position for him. In the last section when we drew him, we just picked +an arbitrary position. Let's do it a little more officially this time. :: + + >>> playerpos = 3 + >>> screen[playerpos] = 8 + >>> print(screen) + [1, 1, 2, 8, 2, 1] + + +Now it is pretty easy to move him to a new position. We simply change +the value of playerpos, and draw him on the screen again. :: + + >>> playerpos = playerpos - 1 + >>> screen[playerpos] = 8 + >>> print(screen) + [1, 1, 8, 8, 2, 1] + + +Whoops. Now we can see two heroes. One in the old position, and one +in his new position. This is exactly the reason we need to "erase" the hero +in his old position before we draw him in the new position. To erase him, +we need to change that value in the list back to what it was before the hero +was there. That means we need to keep track of the values on the screen before +the hero replaced them. There's several ways you could do this, but the easiest +is usually to keep a separate copy of the screen background. This means +we need to make some changes to our little game. + + +Creating A Map +-------------- + +What we want to do is create a separate list we will call our background. +We will create the background so it looks like our original screen did, +with 1s and 2s. Then we will copy each item from the background to the screen. +After that we can finally draw our hero back onto the screen. :: + + >>> background = [1, 1, 2, 2, 2, 1] + >>> screen = [0]*6 #a new blank screen + >>> for i in range(6): + ... screen[i] = background[i] + >>> print(screen) + [1, 1, 2, 2, 2, 1] + >>> playerpos = 3 + >>> screen[playerpos] = 8 + >>> print(screen) + [1, 1, 2, 8, 2, 1] + + +It may seem like a lot of extra work. We're no farther off than we were +before the last time we tried to make him move. But this time we have the +extra information we need to move him properly. + + +Making The Hero Move (Take 2) +----------------------------- + +This time it will be easy to move the hero around. First we will erase +the hero from his old position. We do this by copying the correct value +from the background onto the screen. Then we will draw the character in his +new position on the screen + + + >>> print(screen) + [1, 1, 2, 8, 2, 1] + >>> screen[playerpos] = background[playerpos] + >>> playerpos = playerpos - 1 + >>> screen[playerpos] = 8 + >>> print(screen) + [1, 1, 8, 2, 2, 1] + + +There it is. The hero has moved one space to the left. We can use this +same code to move him to the left again. :: + + >>> screen[playerpos] = background[playerpos] + >>> playerpos = playerpos - 1 + >>> screen[playerpos] = 8 + >>> print(screen) + [1, 8, 2, 2, 2, 1] + + +Excellent! This isn't exactly what you'd call smooth animation. But with +a couple small changes, we'll make this work directly with graphics on +the screen. + + +Definition: "blit" +------------------ + +In the next sections we will transform our program from using lists to +using real graphics on the screen. When displaying the graphics we will +use the term **blit** frequently. If you are new to doing graphics +work, you are probably unfamiliar with this common term. + +BLIT: Basically, blit means to copy graphics from one image +to another. A more formal definition is to copy an array of data +to a bitmapped array destination. You can think of blit as just +*"assigning"* pixels. Much like setting values in our screen-list +above, blitting assigns the color of pixels in our image. + +Other graphics libraries will use the word *bitblt*, or just *blt*, +but they are talking about the same thing. It is basically copying +memory from one place to another. Actually, it is a bit more advanced than +straight copying of memory, since it needs to handle things like pixel +formats, clipping, and scanline pitches. Advanced blitters can also +handle things like transparency and other special effects. + + +Going From The List To The Screen +--------------------------------- + +To take the code we see in the above to examples and make them work with +pygame is very straightforward. We'll pretend we have loaded some pretty +graphics and named them "terrain1", "terrain2", and "hero". Where before +we assigned numbers to a list, we now blit graphics to the screen. Another +big change, instead of using positions as a single index (0 through 5), we +now need a two dimensional coordinate. We'll pretend each of the graphics +in our game is 10 pixels wide. :: + + >>> background = [terrain1, terrain1, terrain2, terrain2, terrain2, terrain1] + >>> screen = create_graphics_screen() + >>> for i in range(6): + ... screen.blit(background[i], (i*10, 0)) + >>> playerpos = 3 + >>> screen.blit(playerimage, (playerpos*10, 0)) + + +Hmm, that code should seem very familiar, and hopefully more importantly; +the code above should make a little sense. Hopefully my illustration of setting +simple values in a list shows the similarity of setting pixels on the screen +(with blit). The only part that's really extra work is converting the player position +into coordinates on the screen. For now we just use a crude :code:`(playerpos*10, 0)` , +but we can certainly do better than that. Now let's move the player +image over a space. This code should have no surprises. :: + + >>> screen.blit(background[playerpos], (playerpos*10, 0)) + >>> playerpos = playerpos - 1 + >>> screen.blit(playerimage, (playerpos*10, 0)) + + +There you have it. With this code we've shown how to display a simple background +with a hero's image on it. Then we've properly moved that hero one space +to the left. So where do we go from here? Well for one the code is still +a little awkward. First thing we'll want to do is find a cleaner way to represent +the background and player position. Then perhaps a bit of smoother, real +animation. + + +Screen Coordinates +------------------ + +To position an object on the screen, we need to tell the blit() function +where to put the image. In pygame we always pass positions as an (X,Y) coordinate. +This represents the number of pixels to the right, and the number of pixels +down to place the image. The top-left corner of a Surface is coordinate (0, +0). Moving to the right a little would be (10, 0), and then moving down just +as much would be (10, 10). When blitting, the position argument represents +where the topleft corner of the source should be placed on the destination. + +Pygame comes with a convenient container for these coordinates, it is a +Rect. The Rect basically represents a rectangular area in these coordinates. +It has topleft corner and a size. The Rect comes with a lot of convenient +methods which help you move and position them. In our next examples we will +represent the positions of our objects with the Rects. + +Also know that many functions in pygame expect Rect arguments. All of these +functions can also accept a simple tuple of 4 elements (left, top, width, +height). You aren't always required to use these Rect objects, but you will +mainly want to. Also, the blit() function can accept a Rect as its position +argument, it simply uses the topleft corner of the Rect as the real position. + + +Changing The Background +----------------------- + +In all our previous sections, we've been storing the background as a list +of different types of ground. That is a good way to create a tile-based game, +but we want smooth scrolling. To make that a little easier, we're going to +change the background into a single image that covers the whole screen. This +way, when we want to "erase" our objects (before redrawing them) we only need +to blit the section of the erased background onto the screen. + +By passing an optional third Rect argument to blit, we tell blit to only +use that subsection of the source image. You'll see that in use below as we +erase the player image. + +Also note, now when we finish drawing to the screen, we call pygame.display.update() +which will show everything we've drawn onto the screen. + + +Smooth Movement +--------------- + +To make something appear to move smoothly, we only want to move it a couple +pixels at a time. Here is the code to make an object move smoothly across +the screen. Based on what we already now know, this should look pretty simple. :: + + >>> screen = create_screen() + >>> clock = pygame.time.Clock() #get a pygame clock object + >>> player = load_player_image() + >>> background = load_background_image() + >>> screen.blit(background, (0, 0)) #draw the background + >>> position = player.get_rect() + >>> screen.blit(player, position) #draw the player + >>> pygame.display.update() #and show it all + >>> for x in range(100): #animate 100 frames + ... screen.blit(background, position, position) #erase + ... position = position.move(2, 0) #move player + ... screen.blit(player, position) #draw new player + ... pygame.display.update() #and show it all + ... clock.tick(60) #update 60 times per second + + +There you have it. This is all the code that is needed to smoothly animate +an object across the screen. We can even use a pretty background character. +Another benefit of doing the background this way, the image for the player +can have transparency or cutout sections and it will still draw correctly +over the background (a free bonus). + +We also throw in a call to pygame.time.Clock() to grab the clock element. +With it, we can call clock.tick() to set the framerate in frames per second. +This slows down our program a little, otherwise it might run so fast you might +not see it. + + +So, What Next? +-------------- + +Well there we have it. Hopefully this article has done everything it promised +to do. But, at this point the code really isn't ready for the next best-selling +game. How do we easily have multiple moving objects? What exactly are those +mysterious functions like load_player_image()? We also need a way to get simple +user input, and loop for more than 100 frames. We'll take the example we +have here, and turn it into an object oriented creation that would make momma +proud. + + +First, The Mystery Functions +---------------------------- + +Full information on these types of functions can be found in other tutorials +and reference. The pygame.image module has a load() function which will do +what we want. The lines to load the images should become this. :: + + >>> player = pygame.image.load('player.bmp').convert() + >>> background = pygame.image.load('liquid.bmp').convert() + + +We can see that's pretty simple, the load function just takes a filename +and returns a new Surface with the loaded image. After loading we make a call +to the Surface method, convert(). Convert returns us a new Surface of the +image, but now converted to the same pixel format as our display. Since the +images will be the same format at the screen, they will blit very quickly. +If we did not convert, the blit() function is slower, since it has to convert +from one type of pixel to another as it goes. + +You may also have noticed that both the load() and convert() return new +Surfaces. This means we're really creating two Surfaces on each of these +lines. In other programming languages, this results in a memory leak (not +a good thing). Fortunately Python is smart enough to handle this, and pygame +will properly clean up the Surface we end up not using. + +The other mystery function we saw in the above example was create_screen(). +In pygame it is simple to create a new window for graphics. The code to create +a 640x480 surface is below. By passing no other arguments, pygame will just +pick the best color depth and pixel format for us. :: + + >>> screen = pygame.display.set_mode((640, 480)) + + +Handling Some Input +------------------- + +We desperately need to change the main loop to look for any user input, (like +when the user closes the window). We need to add "event handling" to our +program. All graphical programs use this Event Based design. The program +gets events like "keyboard pressed" or "mouse moved" from the computer. Then +the program responds to the different events. Here's what the code should +look like. Instead of looping for 100 frames, we'll keep looping until the +user asks us to stop. :: + + >>> while True: + ... for event in pygame.event.get(): + ... if event.type == pygame.QUIT: + ... sys.exit() + ... move_and_draw_all_game_objects() + + +What this code simply does is, first loop forever, then check if there are +any events from the user. We exit the program if the user presses the close +button on the window. After we've checked all the events we move and draw +our game objects. (We'll also erase them before they move, too) + + +Moving Multiple Images +---------------------- + +Here's the part where we're really going to change things around. Let's +say we want 10 different images moving around on the screen. A good way to +handle this is to use python's classes. We'll create a class that represents +our game object. This object will have a function to move itself, and then +we can create as many as we like. The functions to draw and move the object +need to work in a way where they only move one frame (or one step) at a time. +Here's the python code to create our class. :: + + >>> class GameObject: + ... def __init__(self, image, height, speed): + ... self.speed = speed + ... self.image = image + ... self.pos = image.get_rect().move(0, height) + ... def move(self): + ... self.pos = self.pos.move(self.speed, 0) + ... if self.pos.right > 600: + ... self.pos.left = 0 + + +So we have two functions in our class. The init function constructs our object. +It positions the object and sets its speed. The move method moves the object +one step. If it's gone too far, it moves the object back to the left. + + +Putting It All Together +----------------------- + +Now with our new object class, we can put together the entire game. Here +is what the main function for our program will look like. :: + + >>> screen = pygame.display.set_mode((640, 480)) + >>> clock = pygame.time.Clock() #get a pygame clock object + >>> player = pygame.image.load('player.bmp').convert() + >>> background = pygame.image.load('background.bmp').convert() + >>> screen.blit(background, (0, 0)) + >>> objects = [] + >>> for x in range(10): #create 10 objects + ... o = GameObject(player, x*40, x) + ... objects.append(o) + >>> while True: + ... for event in pygame.event.get(): + ... if event.type == pygame.QUIT: + ... sys.exit() + ... for o in objects: + ... screen.blit(background, o.pos, o.pos) + ... for o in objects: + ... o.move() + ... screen.blit(o.image, o.pos) + ... pygame.display.update() + ... clock.tick(60) + + +And there it is. This is the code we need to animate 10 objects on the screen. +The only point that might need explaining is the two loops we use to clear +all the objects and draw all the objects. In order to do things properly, +we need to erase all the objects before drawing any of them. In our sample +here it may not matter, but when objects are overlapping, using two loops +like this becomes important. + + +Preparing for Improved User Input +--------------------------------- + +With all keyboard input terminating the program, that's not very interactive. +Let's add some extra user input! + +First we should create a unique character that the player will control. We +can do that in much the same way we created the other movable entities. Let's +call the player object p. We can already move any object, but, a player should +have more input than simply moving right. To accommodate this, let's revamp +our move function under our GameObject class. :: + + >>> def move(self, up=False, down=False, left=False, right=False): + ... if right: + ... self.pos.right += self.speed + ... if left: + ... self.pos.right -= self.speed + ... if down: + ... self.pos.top += self.speed + ... if up: + ... self.pos.top -= self.speed + ... if self.pos.right > WIDTH: + ... self.pos.left = 0 + ... if self.pos.top > HEIGHT-SPRITE_HEIGHT: + ... self.pos.top = 0 + ... if self.pos.right < SPRITE_WIDTH: + ... self.pos.right = WIDTH + ... if self.pos.top < 0: + ... self.pos.top = HEIGHT-SPRITE_HEIGHT + +There's certainly a lot more going on here, so let's take it one step at a time. +First, we've added some default values into the move function, declared as up, +down, left, and right. These booleans will allow us to specifically select a +direction that the object is moving in. The first part, where we go through and +check True for each variable, is where we will add to the position of the object, +much like before. Right controls horizontal, and top controls vertical positions. + +Additionally, we've removed the magic number present previously, and replaced it +with the constants WIDTH, HEIGHT, SPRITE_WIDTH, and SPRITE_HEIGHT. These values +represent the screen width and height, along with the width and height of the object +displayed on the screen. + +The second part, where the position is being checked, ensures that the position +is within the confines of our screen. With this in place, we need to make sure that +when one of our other objects calls move, we set right to true. + + +Adding the User Input +--------------------- + +We've already seen that pygame has event handling, and we know that KEYDOWN is +an event in this loop. We could, under KEYDOWN, assert the key press matches an +arrow key, where we would then call move. However, this movement will only occur +once every time a key is pressed, and it therefore will be extremely choppy and +unpleasant. + +For this, we can use pygame.key.get_pressed(), which returns a list of all keys, +and whether or not they are currently pressed. Since we want these key presses +to be maintained whether an event is currently happening or not, we should put +it outside of the main event handling loop, but still within our game loop. +Our functionality will look like this. :: + + >>> keys = pygame.key.get_pressed() + >>> if keys[pygame.K_UP]: + ... p.move(up=True) + >>> if keys[pygame.K_DOWN]: + ... p.move(down=True) + >>> if keys[pygame.K_LEFT]: + ... p.move(left=True) + >>> if keys[pygame.K_RIGHT]: + ... p.move(right=True) + +We simply get our list of keys pressed, called keys. We can then check the index +at the key code position to see if it is held down. For more key codes, I recommend +checking out the documentation on pygame.key. + +When up is held, we move our object, p, up. When down is held, we move down. Rinse and +repeat for all cases, and we're good to go! + + +Putting it all Together One More time +------------------------------------- + +Now that we're finished with the player functionality, let's take one last look to make +sure we understand everything. :: + + >>> screen = pygame.display.set_mode((640, 480)) + >>> clock = pygame.time.Clock() #get a pygame clock object + >>> player = pygame.image.load('player.bmp').convert() + >>> entity = pygame.image.load('alien1.bmp').convert() + >>> background = pygame.image.load('background.bmp').convert() + >>> screen.blit(background, (0, 0)) + >>> objects = [] + >>> p = GameObject(player, 10, 3) #create the player object + >>> for x in range(10): #create 10 objects + ... o = GameObject(entity, x*40, x) + ... objects.append(o) + >>> while True: + ... screen.blit(background, p.pos, p.pos) + ... for o in objects: + ... screen.blit(background, o.pos, o.pos) + ... keys = pygame.key.get_pressed() + ... if keys[pygame.K_UP]: + ... p.move(up=True) + ... if keys[pygame.K_DOWN]: + ... p.move(down=True) + ... if keys[pygame.K_LEFT]: + ... p.move(left=True) + ... if keys[pygame.K_RIGHT]: + ... p.move(right=True) + ... for event in pygame.event.get(): + ... if event.type == pygame.QUIT: + ... sys.exit() + ... screen.blit(p.image, p.pos) + ... for o in objects: + ... o.move() + ... screen.blit(o.image, o.pos) + ... pygame.display.update() + ... clock.tick(60) + +A few things not mentioned earlier: we load in a second image and call it entity, +and we use that for all objects that aren't the player, which uses the player +image defined earlier. + +And that's all there is to it! Now we have a fully functional player object that +is controlled using the arrow keys! + + +You Are On Your Own From Here +----------------------------- + +So what would be next on your road to learning? Well first playing around +with this example a bit. The full running version of this example is available +in the pygame examples directory. It is the example named +:func:`moveit.py ` . +Take a look at the code and play with it, run it, learn it. + +Things you may want to work on is maybe having more than one type of object. +Finding a way to cleanly "delete" objects when you don't want to show them +any more. Also updating the display.update() call to pass a list of the areas +on-screen that have changed. + +There are also other tutorials and examples in pygame that cover these +issues. So when you're ready to keep learning, keep on reading. :-) + +Lastly, you can feel free to come to the pygame mailing list or chatroom +with any questions on this stuff. There's always folks on hand who can help +you out with this sort of business. + +Lastly, have fun, that's what games are for! diff --git a/docs/tut/PygameIntro.rst b/docs/tut/PygameIntro.rst new file mode 100644 index 0000000..fa27ca8 --- /dev/null +++ b/docs/tut/PygameIntro.rst @@ -0,0 +1,301 @@ +.. TUTORIAL:Pygame Python Introduction + +.. include:: common.txt + +**************** + Pygame Intro +**************** + + +Python Pygame Introduction +========================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + + +This article is an introduction to the `pygame library `_ +for `Python programmers `_. +The original version appeared in the `PyZine volume 1 issue 3 +`_. +This version contains minor revisions, to +create an all-around better article. Pygame is a Python extension +library that wraps the `SDL `_ library +and its helpers. + + +HISTORY +------- + +Pygame started in the summer of 2000. Being a C programmer of many +years, I discovered both Python and SDL at about the same time. You are +already familiar with Python, which was at version 1.5.2. You may need +an introduction to SDL, which is the Simple DirectMedia Layer. +Created by Sam Lantinga, SDL is a cross-platform C library for +controlling multimedia, comparable to DirectX. It has been used for +hundreds of commercial and open source games. I was impressed at how clean +and straightforward both projects were and it wasn't long before I +realized mixing Python and SDL was an interesting proposal. + +I discovered a small project already under-way with exactly the same +idea, PySDL. Created by Mark Baker, PySDL was a straightforward +implementation of SDL as a Python extension. The interface was cleaner +than a generic SWIG wrapping, but I felt it forced a "C style" of code. +The sudden death of PySDL prompted me to take on a new project of my +own. + +I wanted to put together a project that really took advantage of +Python. My goal was to make it easy to do the simple things, and +straightforward to do the difficult things. Pygame was started in +October, 2000. Six months later pygame version 1.0 was released. + + +TASTE +----- + + +I find the best way to understand a new library is to jump straight +into an example. In the early days of pygame, I created a bouncing ball +animation with 7 lines of code. Let's take a look at a friendlier +version of that same thing. This should be simple enough to follow +along, and a complete breakdown follows. + +.. image:: intro_ball.gif + :class: inlined-right + +.. code-block:: python + + import sys, pygame + pygame.init() + + size = width, height = 320, 240 + speed = [2, 2] + black = 0, 0, 0 + + screen = pygame.display.set_mode(size) + + ball = pygame.image.load("intro_ball.gif") + ballrect = ball.get_rect() + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: sys.exit() + + ballrect = ballrect.move(speed) + if ballrect.left < 0 or ballrect.right > width: + speed[0] = -speed[0] + if ballrect.top < 0 or ballrect.bottom > height: + speed[1] = -speed[1] + + screen.fill("black") + screen.blit(ball, ballrect) + pygame.display.flip() + +This is as simple as you can get for a bouncing animation. +First we see importing and initializing pygame is nothing noteworthy. +The ``import pygame`` imports the package with all the available +pygame modules. +The call to ``pygame.init()`` initializes each of these modules. +Make sure the gif file of the bouncing ball is in the same folder +as the code block. +On :clr:`line 4` we set the size of the display window, for best +results you can change these numbers to match your own monitor's +resolution. +On :clr:`line 8` we create a +graphical window with the call to ``pygame.display.set_mode()``. +Pygame and SDL make this easy by defaulting to the best graphics modes +for the graphics hardware. You can override the mode and SDL will +compensate for anything the hardware cannot do. Pygame represents +images as *Surface* objects. +The ``display.set_mode()`` function creates a new *Surface* +object that represents the actual displayed graphics. Any drawing you +do to this Surface will become visible on the monitor. + +At :clr:`line 10` we load +our ball image. Pygame supports a variety of image formats through the +SDL_image library, including BMP, JPG, PNG, TGA, and GIF. +The ``pygame.image.load()`` function +returns us a Surface with the ball data. The Surface will keep any +colorkey or alpha transparency from the file. After loading the ball +image we create a variable named ballrect. Pygame comes with a +convenient utility object type named :class:`Rect `, +which represents a rectangular area. Later, in the animation part of +the code, we will see what the *Rect* objects can do. + +At this point, :clr:`line 13`, +our program is initialized and ready to run. Inside an infinite loop we +check for user input, move the ball, and then draw the ball. If you are +familiar with GUI programming, you have had experience with events and +event loops. In pygame this is no different, +we check if a *QUIT* event has happened. If so we +simply exit the program, pygame will ensure everything is cleanly +shutdown. + +It is time to update our position for the ball. +:clr:`Lines 17` moves the ballrect variable by the current speed. +:clr:`Lines 18 thru 21` reverse the speed if the ball has moved outside the screen. +Not exactly Newtonian physics, but it is all we need. + +On :clr:`line 23` we erase +the screen by filling it with a black RGB color. If you have never +worked with animations this may seem strange. You may be asking "Why do +we need to erase anything, why don't we just move the ball on the +screen?" That is not quite the way computer animation works. Animation +is nothing more than a series of single images, which when displayed in +sequence do a very good job of fooling the human eye into seeing +motion. The screen is just a single image that the user sees. If we did +not take the time to erase the ball from the screen, we would actually +see a "trail" of the ball as we continuously draw the ball in its new +positions. + +On :clr:`line 24` we draw the ball image onto the screen. +Drawing of images is handled by the +:meth:`Surface.blit() ` method. +A blit basically means copying pixel colors from one image to another. +We pass the blit method a source :class:`Surface ` +to copy from, and a position to place the source onto the destination. + +The last thing we need to do is actually update the visible display. +Pygame manages the display with a double buffer. When we are finished +drawing we call the :func:`pygame.display.flip()` method. +This makes everything we have drawn on the screen Surface +become visible. This buffering makes sure we only see completely drawn +frames on the screen. Without it, the user would see the half completed +parts of the screen as they are being created. + +That concludes this short introduction to pygame. Pygame also has +modules to do things like input handling for the keyboard, mouse, and +joystick. It can mix audio and decode streaming music. +With the *Surfaces* you can draw simple +shapes, rotate and scale the picture, and even manipulate the pixels of +an image in realtime as numpy arrays. +Pygame also has the ability to act as a +cross platform display layer for PyOpenGL. Most of the pygame modules +are written in C, few are actually done in Python. + +The pygame website has full reference documentation for every pygame +function and tutorials for all ranges of users. The pygame source comes +with many examples of things like monkey punching and UFO shooting. + + +PYTHON AND GAMING +----------------- + +"Is Python suitable for gaming?" The answer is, "It depends on the +game." + +Python is actually quite capable at running games. It will likely even +surprise you how much is possible in under 30 milliseconds. Still, it +is not hard to reach the ceiling once your game begins to get more +complex. Any game running in realtime will be making full use of the +computer. + +.. image:: intro_blade.jpg + :class: inlined-right + +Over the past several years there has been an interesting trend in game development, +the move towards higher level languages. Usually a game is split into +two major parts. The game engine, which must be as fast as possible, +and the game logic, which makes the engine actually do something. It +wasn't long ago when the engine of a game was written in assembly, with +portions written in C. Nowadays, C has moved to the game engine, while +often the game itself is written in higher level scripting languages. +Games like Quake3 and Unreal run these scripts as portable bytecode. + +In early 2001, developer Rebel Act Studios finished their game, +Severance: Blade of Darkness. Using their own custom 3D engine, the +rest of the game is written with Python. The game is a bloody action +3rd person perspective fighter. You control medieval warriors into +intricate decapitating combination attacks while exploring dungeons and +castles. You can download third party add-ons for this game, and find +they are nothing more than Python source files. + +More recently, Python has been used in a variety of games like Freedom +Force, and Humungous' Backyard Sports Series. + +.. image:: intro_freedom.jpg + :class: inlined-right + +Pygame and SDL serve as an excellent C engine for 2D games. +Games will still find the largest part of their runtime is spent +inside SDL handling the graphics. +SDL can take advantage of graphics hardware acceleration. +Enabling this can change a game from running around 40 frames per +second to over 200 frames per second. When you see your Python game +running at 200 frames per second, you realize that Python and games can +work together. + +It is impressive how well both Python and SDL work on multiple +platforms. For example, in May of 2001 I released my own full pygame +project, SolarWolf, an arcade style action game. One thing that has +surprised me is that one year later there has been no need for any +patches, bug fixes, or updates. The game was developed entirely on +windows, but runs on Linux, Mac OSX, and many Unixes without any extra +work on my end. + +Still, there are very clear limitations. The best way to manage +hardware accelerated graphics is not always the way to get fastest +results from software rendering. Hardware support is not available on +all platforms. When a game gets more complex, it often must commit to +one or the other. SDL has some other design limitations, things like +full screen scrolling graphics can quickly bring your game down to +unplayable speeds. While SDL is not suitable for all types of games, +remember companies like Loki have used SDL to run a wide variety of +retail quality titles. + +Pygame is fairly low-level when it comes to writing games. You'll +quickly find yourself needing to wrap common functions into your own +game environment. The great thing about this is there is nothing inside +pygame to get in your way. Your program is in full control of +everything. The side effect of that is you will find yourself borrowing +a lot of code to get a more advanced framework put together. You'll +need a better understanding of what you are doing. + + +CLOSING +------- + +Developing games is very rewarding, there is something exciting about +being able to see and interact with the code you've written. Pygame +currently has almost 30 other projects using it. Several of them are +ready to play now. You may be surprised to visit the pygame website, +and see what other users have been able to do with Python. + +One thing that has caught my attention is the amount of people coming +to Python for the first time to try game development. I can see why +games are a draw for new programmers, but it can be difficult since +creating games requires a firmer understanding of the language. I've +tried to support this group of users by writing many examples and +pygame tutorials for people new to these concepts. + +In the end, my advice is to keep it simple. I cannot stress this +enough. If you are planning to create your first game, there is a +lot to learn. Even a simpler game will challenge your designs, and +complex games don't necessarily mean fun games. When you understand +Python, you can use pygame to create a simple game in only one or two +weeks. From there you'll need a surprising amount of time to add +the polish to make that into a full presentable game. + +Pygame Modules Overview +^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :class: more-to-explore + :widths: 20, 50 + + :mod:`cdrom `, "playback" + :mod:`cursors `, "load cursor images, includes standard cursors" + :mod:`display `, "control the display window or screen" + :mod:`draw `, "draw simple shapes onto a Surface" + :mod:`event `, "manage events and the event queue" + :mod:`font `, "create and render TrueType fonts" + :mod:`image `, "save and load images" + :mod:`joystick `, "manage joystick devices" + :mod:`key `, "manage the keyboard" + :mod:`mouse `, "manage the mouse" + :mod:`sndarray `, "manipulate sounds with numpy" + :mod:`surfarray `, "manipulate images with numpy" + :mod:`time `, "control timing" + :mod:`transform `, "scale, rotate, and flip images" diff --git a/docs/tut/SpriteIntro.rst b/docs/tut/SpriteIntro.rst new file mode 100644 index 0000000..1ba571f --- /dev/null +++ b/docs/tut/SpriteIntro.rst @@ -0,0 +1,415 @@ +.. TUTORIAL: Sprite Module Introduction + +.. include:: common.txt + +************************************************* + Pygame Tutorials - Sprite Module Introduction +************************************************* + + +Sprite Module Introduction +========================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + +Pygame version 1.3 comes with a new module, ``pygame.sprite``. This module is +written in Python and includes some higher-level classes to manage your game +objects. By using this module to its full potential, you can easily manage and +draw your game objects. The sprite classes are very optimized, so it's likely +your game will run faster with the sprite module than without. + +The sprite module is also meant to be very generic. It turns out you can use it +with nearly any type of gameplay. All this flexibility comes with a slight +penalty, it needs a little understanding to properly use it. The +:mod:`reference documentation ` for the sprite module can keep +you running, but you'll probably need a bit more explanation of how to use +``pygame.sprite`` in your own game. + +Several of the pygame examples (like "chimp" and "aliens") have been updated to +use the sprite module. You may want to look into those first to see what this +sprite module is all about. The chimp module even has its own line-by-line +tutorial, which may help get more an understanding of programming with python +and pygame. + +Note that this introduction will assume you have a bit of experience +programming with python, and are somewhat familiar with the different parts of +creating a simple game. In this tutorial the word "reference" is occasionally +used. This represents a python variable. Variables in python are references, +so you can have several variables all pointing to the same object. + +History Lesson +-------------- + +The term "sprite" is a holdover from older computer and game machines. These +older boxes were unable to draw and erase normal graphics fast enough for them +to work as games. These machines had special hardware to handle game like +objects that needed to animate very quickly. These objects were called +"sprites" and had special limitations, but could be drawn and updated very +fast. They usually existed in special overlay buffers in the video. These days +computers have become generally fast enough to handle sprite like objects +without dedicated hardware. The term sprite is still used to represent just +about anything in a 2D game that is animated. + +The Classes +----------- + +The sprite module comes with two main classes. The first is :class:`Sprite +`, which should be used as a base class for all your game +objects. This class doesn't really do anything on its own, it just includes +several functions to help manage the game object. The other type of class is +:class:`Group `. The ``Group`` class is a container for +different ``Sprite`` objects. There are actually several different types of +group classes. Some of the ``Groups`` can draw all the elements they contain, +for example. + +This is all there really is to it. We'll start with a description of what each +type of class does, and then discuss the proper ways to use these two classes. + + +The Sprite Class +---------------- + +As mentioned before, the Sprite class is designed to be a base class for all +your game objects. You cannot really use it on its own, as it only has several +methods to help it work with the different ``Group`` classes. The sprite keeps +track of which groups it belongs to. +The class constructor (``__init__`` method) takes an argument of a +``Group`` (or list of ``Groups``) the ``Sprite`` instance should belong to. +You can also change the ``Group`` membership for the ``Sprite`` with the +:meth:`add() ` and +:meth:`remove() ` methods. +There is also a :meth:`groups() ` method, +which returns a list of the current groups containing the sprite. + +When using the your Sprite classes it's best to think of them as "valid" or +"alive" when they are belonging to one or more ``Groups``. When you remove the +instance from all groups pygame will clean up the object. (Unless you have your +own references to the instance somewhere else.) The :meth:`kill() +` method removes the sprite from all groups it +belongs to. This will cleanly delete the sprite object. If you've put some +little games together, you'll know sometimes cleanly deleting a game object can +be tricky. The sprite also comes with an :meth:`alive() +` method, which returns true if it is still a +member of any groups. + + +The Group Class +--------------- + +The ``Group`` class is just a simple container. Similar to the sprite, it has +an :meth:`add() ` and :meth:`remove() +` method which can change which sprites belong to +the group. You also can pass a sprite or list of sprites to the constructor +(``__init__()`` method) to create a ``Group`` instance that contains some +initial sprites. + + +The ``Group`` has a few other methods like :meth:`empty() +` to remove all sprites from the group and +:meth:`copy() ` which will return a copy of the group +with all the same members. Also the :meth:`has() ` +method will quickly check if the ``Group`` contains a sprite or list of +sprites. + +The other function you will use frequently is the :meth:`sprites() +` method. This returns an object that can be +looped on to access every sprite the group contains. Currently this is just a +list of the sprites, but in later version of python this will likely use +iterators for better performance. + +As a shortcut, the ``Group`` also has an :meth:`update() +` method, which will call an ``update()`` method on +every sprite in the group. Passing the same arguments to each one. Usually in a +game you need some function that updates the state of a game object. It's very +easy to call your own methods using the ``Group.sprites()`` method, but this is +a shortcut that's used enough to be included. Also note that the base +``Sprite`` class has a "dummy" ``update()`` method that takes any sort of +arguments and does nothing. + +Lastly, the Group has a couple other methods that allow you to use it with +the builtin ``len()`` function, getting the number of sprites it contains, and +the "truth" operator, which allows you to do "if mygroup:" to check if the +group has any sprites. + + +Mixing Them Together +-------------------- + +At this point the two classes seem pretty basic. Not doing a lot more than you +can do with a simple list and your own class of game objects. But there are +some big advantages to using the ``Sprite`` and ``Group`` together. A sprite +can belong to as many groups as you want. Remember as soon as it belongs to no +groups, it will usually be cleared up (unless you have other "non-group" +references to that object). + +The first big thing is a fast simple way to categorize sprites. For example, +say we had a Pacman-like game. We could make separate groups for the different +types of objects in the game. Ghosts, Pac, and Pellets. When Pac eats a power +pellet, we can change the state for all ghost objects by effecting everything +in the Ghost group. This is quicker and simpler than looping through a list +of all the game objects and checking which ones are ghosts. + +Adding and removing groups and sprites from each other is a very fast +operation, quicker than using lists to store everything. Therefore you can very +efficiently change group memberships. Groups can be used to work like simple +attributes for each game object. Instead of tracking some attribute like +"close_to_player" for a bunch of enemy objects, you could add them to a +separate group. Then when you need to access all the enemies that are near the +player, you already have a list of them, instead of going through a list of all +the enemies, checking for the "close_to_player" flag. Later on your game could +add multiple players, and instead of adding more "close_to_player2", +"close_to_player3" attributes, you can easily add them to different groups for +each player. + +Another important benefit of using the ``Sprites`` and ``Groups`` is that the groups +cleanly handle the deleting (or killing) of game objects. In a game where many +objects are referencing other objects, sometimes deleting an object can be the +hardest part, since it can't go away until it is not referenced by anyone. Say +we have an object that is "chasing" another object. The chaser can keep a +simple Group that references the object (or objects) it is chasing. If the +object being chased happens to be destroyed, we don't need to worry about +notifying the chaser to stop chasing. The chaser can see for itself that its +group is now empty, and perhaps find a new target. + +Again, the thing to remember is that adding and removing sprites from groups is +a very cheap/fast operation. You may be best off by adding many groups to +contain and organize your game objects. Some could even be empty for large +portions of the game, there isn't any penalties for managing your game like +this. + + +The Many Group Types +-------------------- + +The above examples and reasons to use ``Sprites`` and ``Groups`` are only a tip +of the iceberg. Another advantage is that the sprite module comes with several +different types of ``Groups``. These groups all work just like a regular old +``Group``, but they also have added functionality (or slightly different +functionality). Here's a list of the ``Group`` classes included with the +sprite module. + + :class:`Group ` + + This is the standard "no frills" group mainly explained above. Most of the + other ``Groups`` are derived from this one, but not all. + + :class:`GroupSingle ` + + This works exactly like the regular ``Group`` class, but it only contains + the most recently added sprite. Therefore when you add a sprite to this group, + it "forgets" about any previous sprites it had. Therefore it always contains + only one or zero sprites. + + :class:`RenderPlain ` + + This is a standard group derived from ``Group``. It has a draw() method + that draws all the sprites it contains to the screen (or any ``Surface``). For + this to work, it requires all sprites it contains to have a "image" and "rect" + attributes. It uses these to know what to blit, and where to blit it. + + :class:`RenderClear ` + + This is derived from the ``RenderPlain`` group, and adds a method named + ``clear()``. This will erase the previous position of all drawn sprites. It + uses a background image to fill in the areas where the sprite were. It is smart + enough to handle deleted sprites and properly clear them from the screen when + the ``clear()`` method is called. + + :class:`RenderUpdates ` + + This is the Cadillac of rendering ``Groups``. It is inherited from + ``RenderClear``, but changes the ``draw()`` method to also return a list of + pygame ``Rects``, which represent all the areas on screen that have been + changed. + +That is the list of different groups available We'll discuss more about these +rendering groups in the next section. There's nothing stopping you from +creating your own Group classes as well. They are just python code, so you can +inherit from one of these and add/change whatever you want. In the future I +hope we can add a couple more ``Groups`` to this list. A ``GroupMulti`` which +is like the ``GroupSingle``, but can hold up to a given number of sprites (in +some sort of circular buffer?). Also a super-render group that can clear the +position of the old sprites without needing a background image to do it (by +grabbing a copy of the screen before blitting). Who knows really, but in the +future we can add more useful classes to this list. + + +The Rendering Groups +-------------------- + +From above we can see there are three different rendering groups. We could +probably just get away with the ``RenderUpdates`` one, but it adds overhead not +really needed for something like a scrolling game. So we have a couple tools +here, pick the right one for the right job. + +For a scrolling type game, where the background completely changes every frame, +we obviously don't need to worry about python's update rectangles in the call +to ``display.update()``. You should definitely go with the ``RenderPlain`` +group here to manage your rendering. + +For games where the background is more stationary, you definitely don't want +pygame updating the entire screen (since it doesn't need to). This type of game +usually involves erasing the old position of each object, then drawing it in a +new place for each frame. This way we are only changing what is necessary. +Most of the time you will just want to use the ``RenderUpdates`` class here. +Since you will also want to pass this list of changes to the +``display.update()`` function. + +The ``RenderUpdates`` class also does a good job at minimizing overlapping +areas in the list of updated rectangles. If the previous position and current +position of an object overlap, it will merge them into a single rectangle. +Combined with the fact that it properly handles deleted objects, this is +one powerful ``Group`` class. If you've written a game that manages the changed +rectangles for the objects in a game, you know this the cause for a lot of +messy code in your game. Especially once you start to throw in objects that can +be deleted at any time. All this work is reduced to a ``clear()`` and +``draw()`` method with this monster class. Plus with the overlap checking, it +is likely faster than when you did it manually. + +Also note that there's nothing stopping you from mixing and matching these +render groups in your game. You should definitely use multiple rendering groups +when you want to do layering with your sprites. Also if the screen is split +into multiple sections, perhaps each section of the screen should use an +appropriate render group? + + +Collision Detection +------------------- + +The sprite module also comes with two very generic collision detection +functions. For more complex games, these really won't work for you, but you +can easily grab the source code for them, and modify them as needed. + +Here's a summary of what they are, and what they do. + + :func:`spritecollide(sprite, group, dokill) -> list ` + + This checks for collisions between a single sprite and the sprites in a group. + It requires a "rect" attribute for all the sprites used. It returns a list of + all the sprites that overlap with the first sprite. The "dokill" argument is a + boolean argument. If it is true, the function will call the ``kill()`` method + on all the sprites. This means the last reference to each sprite is probably in + the returned list. Once the list goes away so do the sprites. A quick example + of using this in a loop :: + + >>> for bomb in sprite.spritecollide(player, bombs, 1): + ... boom_sound.play() + ... Explosion(bomb, 0) + + This finds all the sprites in the "bomb" group that collide with the player. + Because of the "dokill" argument it deletes all the crashed bombs. For each + bomb that did collide, it plays a "boom" sound effect, and creates a new + ``Explosion`` where the bomb was. (Note, the ``Explosion`` class here knows to + add each instance to the appropriate class, so we don't need to store it in a + variable, that last line might feel a little "funny" to you python programmers.) + + :func:`groupcollide(group1, group2, dokill1, dokill2) -> dictionary ` + + This is similar to the ``spritecollide`` function, but a little more complex. + It checks for collisions for all the sprites in one group, to the sprites in + another. There is a ``dokill`` argument for the sprites in each list. When + ``dokill1`` is true, the colliding sprites in ``group1`` will be ``kill()``ed. + When ``dokill2`` is true, we get the same results for ``group2``. The + dictionary it returns works like this; each key in the dictionary is a sprite + from ``group1`` that had a collision. The value for that key is a list of the + sprites that it collided with. Perhaps another quick code sample explains it + best :: + + >>> for alien in sprite.groupcollide(aliens, shots, 1, 1).keys() + ... boom_sound.play() + ... Explosion(alien, 0) + ... kills += 1 + + This code checks for the collisions between player bullets and all the aliens + they might intersect. In this case we only loop over the dictionary keys, but + we could loop over the ``values()`` or ``items()`` if we wanted to do something + to the specific shots that collided with aliens. If we did loop over the + ``values()`` we would be looping through lists that contain sprites. The same + sprite may even appear more than once in these different loops, since the same + "shot" could have collided against multiple "aliens". + +Those are the basic collision functions that come with pygame. It should be +easy to roll your own that perhaps use something different than the "rect" +attribute. Or maybe try to fine-tweak your code a little more by directly +effecting the collision object, instead of building a list of the collision? +The code in the sprite collision functions is very optimized, but you could +speed it up slightly by taking out some functionality you don't need. + + +Common Problems +--------------- + +Currently there is one main problem that catches new users. When you derive +your new sprite class with the Sprite base, you **must** call the +``Sprite.__init__()`` method from your own class ``__init__()`` method. If you +forget to call the ``Sprite.__init__()`` method, you get a cryptic error, like +this :: + + AttributeError: 'mysprite' instance has no attribute '_Sprite__g' + + +Extending Your Own Classes *(Advanced)* +--------------------------------------- + +Because of speed concerns, the current ``Group`` classes try to only do exactly +what they need, and not handle a lot of general situations. If you decide you +need extra features, you may want to create your own ``Group`` class. + +The ``Sprite`` and ``Group`` classes were designed to be extended, so feel free +to create your own ``Group`` classes to do specialized things. The best place +to start is probably the actual python source code for the sprite module. +Looking at the current ``Sprite`` groups should be enough example on how to +create your own. + +For example, here is the source code for a rendering ``Group`` that calls a +``render()`` method for each sprite, instead of just blitting an "image" +variable from it. Since we want it to also handle updated areas, we will start +with a copy of the original ``RenderUpdates`` group, here is the code:: + + class RenderUpdatesDraw(RenderClear): + """call sprite.draw(screen) to render sprites""" + def draw(self, surface): + dirty = self.lostsprites + self.lostsprites = [] + for s, r in self.spritedict.items(): + newrect = s.draw(screen) #Here's the big change + if r is 0: + dirty.append(newrect) + else: + dirty.append(newrect.union(r)) + self.spritedict[s] = newrect + return dirty + +Following is more information on how you could create your own ``Sprite`` and +``Group`` objects from scratch. + +The ``Sprite`` objects only "require" two methods. "add_internal()" and +"remove_internal()". These are called by the ``Group`` classes when they are +removing a sprite from themselves. The ``add_internal()`` and +``remove_internal()`` have a single argument which is a group. Your ``Sprite`` +will need some way to also keep track of the ``Groups`` it belongs to. You will +likely want to try to match the other methods and arguments to the real +``Sprite`` class, but if you're not going to use those methods, you sure don't +need them. + +It is almost the same requirements for creating your own ``Group``. In fact, if +you look at the source you'll see the ``GroupSingle`` isn't derived from the +``Group`` class, it just implements the same methods so you can't really tell +the difference. Again you need an "add_internal()" and "remove_internal()" +method that the sprites call when they want to belong or remove themselves from +the group. The ``add_internal()`` and ``remove_internal()`` have a single +argument which is a sprite. The only other requirement for the ``Group`` +classes is they have a dummy attribute named "_spritegroup". It doesn't matter +what the value is, as long as the attribute is present. The Sprite classes can +look for this attribute to determine the difference between a "group" and any +ordinary python container. (This is important, because several sprite methods +can take an argument of a single group, or a sequence of groups. Since they +both look similar, this is the most flexible way to "see" the difference.) + +You should go through the code for the sprite module. While the code is a bit +"tuned", it's got enough comments to help you follow along. There's even a +TODO section in the source if you feel like contributing. + diff --git a/docs/tut/SurfarrayIntro-rest b/docs/tut/SurfarrayIntro-rest new file mode 100644 index 0000000..5d9690a --- /dev/null +++ b/docs/tut/SurfarrayIntro-rest @@ -0,0 +1,114 @@ + +Hopefully by this point you are starting to see how surfarray can be used to +perform special effects and transformations that are only possible at the pixel +level. At the very least, you can use the surfarray to do a lot of Surface.set_at() +Surface.get_at() type operations very quickly. But don't think you are finished +yet, there is still much to learn. + + + +Surface Locking +=============== + +Like the rest of pygame, surfarray will lock any Surfaces it needs to +automatically when accessing pixel data. There is one extra thing to be aware +of though. When creating the *pixel* arrays, the original surface will +be locked during the lifetime of that pixel array. This is important to remember. +Be sure to *"del"* the pixel array or let it go out of scope *(ie, when the function returns, etc)*. + +Also be aware that you really don't want to be doing much *(if any)* +direct pixel access on hardware surfaces *(HWSURFACE)*. This is because +the actual surface data lives on the graphics card, and transferring pixel +changes over the PCI/AGP bus is not fast. + + + + +Transparency +============ + +.. comment out + The surfarray module has several methods for accessing a Surface's alpha/colorkey + values. None of the alpha functions are effected by overal transparency of a + Surface, just the pixel alpha values. Here's the list of those functions. +
+
``surfarray.pixels_alpha(surface)``
Creates a 2D array *(integer pixel values)* that references the original surface alpha data. This will only + work on 32bit images with an 8bit alpha component.
+ +
``surfarray.array_alpha(surface)``
Creates a 2D array *(integer pixel values)* that is copied from any type of surface. If the surface has no alpha + values, the array will be fully opaque values *(255)*. + +
``surfarray.array_colorkey(surface)``
Creates a 2D array + *(integer pixel values)* that is set to transparent *(0)* wherever + that pixel color matches the Surface colorkey. + +
+ + + +Other Surfarray Functions +========================= + +.. comment out + There are only a few other functions available in surfarray. + You can get a better list with more documentation on the + :mod:`surfarray reference page `. + There is one very useful function though. +
+
``surfarray.blit_array(surface, array)``
This will transfer + any type of 2D or 3D surface array onto a Surface of the same dimensions. + This surfarray blit will generally be faster than assigning an array to a + referenced pixel array. Still, it should not be as fast as normal Surface + blitting, since those are very optimized. +
+
+ + + + +More Advanced NumPy +===================== + +There's a couple last things you should know about NumPy arrays. When dealing +with very large arrays, like the kind that are 640x480 big, there are some extra +things you should be careful about. Mainly, while using the operators like + and +* on the arrays makes them easy to use, it is also very expensive on big arrays. +These operators must make new temporary copies of the array, that are then +usually copied into another array. This can get very time consuming. Fortunately, +all the NumPy operators come with special functions that can perform the +operation *"in place"*. For example, you would want to replace +``screen[:] = screen + brightmap`` with the much faster +``add(screen, brightmap, screen)``. +Anyways, you'll want to read up on the NumPy UFunc +documentation for more about this. It is important when dealing with the arrays. + +When dealing with the 16bit pixel arrays, NumPy doesn't offer an unsigned 16bit +datatype, so some values will be treated as signed. Hopefully this does not +present a problem. + +Another thing to be aware of when working with NumPy arrays is the datatype +of the array. Some of the arrays (especially the mapped pixel type) often return +arrays with an unsigned 8bit value. These arrays will easily overflow if you are +not careful. NumPy will use the same coercion that you find in C programs, so +mixing an operation with 8bit numbers and 32bit numbers will give a result as +32bit numbers. You can convert the datatype of an array, but definitely be +aware of what types of arrays you have, if NumPy gets in a situation where +precision would be ruined, it will raise an exception. + +Lastly, be aware that when assigning values into the 3D arrays, they must be +between 0 and 255, or you will get some undefined truncating. + + + +Graduation +========== + +Well there you have it. My quick primer on Numeric Python and surfarray. +Hopefully now you see what is possible, and even if you never use them for +yourself, you do not have to be afraid when you see code that does. Look into +the vgrade example for more numeric array action. There are also some *"flame"* +demos floating around that use surfarray to create a realtime fire effect. + +Best of all, try some things on your own. Take it slow at first and build up, +I've seen some great things with surfarray already like radial gradients and +more. Good Luck. diff --git a/docs/tut/SurfarrayIntro.rst b/docs/tut/SurfarrayIntro.rst new file mode 100644 index 0000000..d29376c --- /dev/null +++ b/docs/tut/SurfarrayIntro.rst @@ -0,0 +1,580 @@ +.. TUTORIAL:Introduction to the surfarray module + +.. include:: common.txt + +********************************************* + Pygame Tutorials - Surfarray Introduction +********************************************* + +.. currentmodule:: surfarray + +Surfarray Introduction +====================== + +.. rst-class:: docinfo + +:Author: Pete Shinners +:Contact: pete@shinners.org + + +Introduction +------------ + +This tutorial will attempt to introduce users to both NumPy and the pygame +surfarray module. To beginners, the code that uses surfarray can be quite +intimidating. But actually there are only a few concepts to understand and +you will be up and running. Using the surfarray module, it becomes possible +to perform pixel level operations from straight python code. The performance +can become quite close to the level of doing the code in C. + +You may just want to jump down to the *"Examples"* section to get an +idea of what is possible with this module, then start at the beginning here +to work your way up. + +Now I won't try to fool you into thinking everything is very easy. To get +more advanced effects by modifying pixel values is very tricky. Just mastering +Numeric Python (SciPy's original array package was Numeric, the predecessor of NumPy) +takes a lot of learning. In this tutorial I'll be sticking with +the basics and using a lot of examples in an attempt to plant seeds of wisdom. +After finishing the tutorial you should have a basic handle on how the surfarray +works. + + +Numeric Python +-------------- + +If you do not have the python NumPy package installed, +you will need to do that now, by following the +`NumPy Installation Guide `_. +To make sure NumPy is working for you, +you should get something like this from the interactive python prompt. :: + + >>> from numpy import * #import numeric + >>> a = array((1,2,3,4,5)) #create an array + >>> a #display the array + array([1, 2, 3, 4, 5]) + >>> a[2] #index into the array + 3 + >>> a*2 #new array with twiced values + array([ 2, 4, 6, 8, 10]) + +As you can see, the NumPy module gives us a new data type, the *array*. +This object holds an array of fixed size, and all values inside are of the same +type. The arrays can also be multidimensional, which is how we will use them +with images. There's a bit more to it than this, but it is enough to get us +started. + +If you look at the last command above, you'll see that mathematical operations +on NumPy arrays apply to all values in the array. This is called "element-wise +operations". These arrays can also be sliced like normal lists. The slicing +syntax is the same as used on standard python objects. +*(so study up if you need to :] )*. +Here are some more examples of working with arrays. :: + + >>> len(a) #get array size + 5 + >>> a[2:] #elements 2 and up + array([3, 4, 5]) + >>> a[:-2] #all except last 2 + array([1, 2, 3]) + >>> a[2:] + a[:-2] #add first and last + array([4, 6, 8]) + >>> array((1,2,3)) + array((3,4)) #add arrays of wrong sizes + Traceback (most recent call last): + File "", line 1, in + ValueError: operands could not be broadcast together with shapes (3,) (2,) + +We get an error on the last command, because we try add together two arrays +that are different sizes. In order for two arrays two operate with each other, +including comparisons and assignment, they must have the same dimensions. It is +very important to know that the new arrays created from slicing the original all +reference the same values. So changing the values in a slice also changes the +original values. It is important how this is done. :: + + >>> a #show our starting array + array([1, 2, 3, 4, 5]) + >>> aa = a[1:3] #slice middle 2 elements + >>> aa #show the slice + array([2, 3]) + >>> aa[1] = 13 #chance value in slice + >>> a #show change in original + array([ 1, 2, 13, 4, 5]) + >>> aaa = array(a) #make copy of array + >>> aaa #show copy + array([ 1, 2, 13, 4, 5]) + >>> aaa[1:4] = 0 #set middle values to 0 + >>> aaa #show copy + array([1, 0, 0, 0, 5]) + >>> a #show original again + array([ 1, 2, 13, 4, 5]) + +Now we will look at small arrays with two +dimensions. Don't be too worried, getting started it is the same as having a +two dimensional tuple *(a tuple inside a tuple)*. Let's get started with +two dimensional arrays. :: + + >>> row1 = (1,2,3) #create a tuple of vals + >>> row2 = (3,4,5) #another tuple + >>> (row1,row2) #show as a 2D tuple + ((1, 2, 3), (3, 4, 5)) + >>> b = array((row1, row2)) #create a 2D array + >>> b #show the array + array([[1, 2, 3], + [3, 4, 5]]) + >>> array(((1,2),(3,4),(5,6))) #show a new 2D array + array([[1, 2], + [3, 4], + [5, 6]]) + +Now with this two +dimensional array *(from now on as "2D")* we can index specific values +and do slicing on both dimensions. Simply using a comma to separate the indices +allows us to lookup/slice in multiple dimensions. Just using "``:``" as an +index *(or not supplying enough indices)* gives us all the values in +that dimension. Let's see how this works. :: + + >>> b #show our array from above + array([[1, 2, 3], + [3, 4, 5]]) + >>> b[0,1] #index a single value + 2 + >>> b[1,:] #slice second row + array([3, 4, 5]) + >>> b[1] #slice second row (same as above) + array([3, 4, 5]) + >>> b[:,2] #slice last column + array([3, 5]) + >>> b[:,:2] #slice into a 2x2 array + array([[1, 2], + [3, 4]]) + +Ok, stay with me here, this is about as hard as it gets. When using NumPy +there is one more feature to slicing. Slicing arrays also allow you to specify +a *slice increment*. The syntax for a slice with increment is +``start_index : end_index : increment``. :: + + >>> c = arange(10) #like range, but makes an array + >>> c #show the array + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> c[1:6:2] #slice odd values from 1 to 6 + array([1, 3, 5]) + >>> c[4::4] #slice every 4th val starting at 4 + array([4, 8]) + >>> c[8:1:-1] #slice 1 to 8, reversed + array([8, 7, 6, 5, 4, 3, 2]) + +Well that is it. There's enough information there to get you started using +NumPy with the surfarray module. There's certainly a lot more to NumPy, but +this is only an introduction. Besides, we want to get on to the fun stuff, +correct? + + +Import Surfarray +---------------- + +In order to use the surfarray module we need to import it. Since both surfarray +and NumPy are optional components for pygame, it is nice to make sure they +import correctly before using them. In these examples I'm going to import +NumPy into a variable named *N*. This will let you know which functions +I'm using are from the NumPy package. +*(and is a lot shorter than typing NumPy before each function)* :: + + try: + import numpy as N + import pygame.surfarray as surfarray + except ImportError: + raise ImportError, "NumPy and Surfarray are required." + + +Surfarray Introduction +---------------------- + + +There are two main types of functions in surfarray. One set of functions for +creating an array that is a copy of a surface pixel data. The other functions +create a referenced copy of the array pixel data, so that changes to the array +directly affect the original surface. There are other functions that allow you +to access any per-pixel alpha values as arrays along with a few other helpful +functions. We will look at these other functions later on. + +When working with these surface arrays, there are two ways of representing the +pixel values. First, they can be represented as mapped integers. This type of +array is a simple 2D array with a single integer representing the surface's +mapped color value. This type of array is good for moving parts of an image +around. The other type of array uses three RGB values to represent each pixel +color. This type of array makes it extremely simple to do types of effects that +change the color of each pixel. This type of array is also a little trickier to +deal with, since it is essentially a 3D numeric array. Still, once you get your +mind into the right mode, it is not much harder than using the normal 2D arrays. + +The NumPy module uses a machine's natural number types to represent the data +values, so a NumPy array can consist of integers that are 8-bits, 16-bits, and 32-bits. +*(the arrays can also use other types like floats and doubles, but for our image +manipulation we mainly need to worry about the integer types)*. +Because of this limitation of integer sizes, you must take a little extra care +that the type of arrays that reference pixel data can be properly mapped to a +proper type of data. The functions create these arrays from surfaces are: + +.. function:: pixels2d(surface) + :noindex: + + Creates a 2D array *(integer pixel values)* that reference the original surface data. + This will work for all surface formats except 24-bit. + +.. function:: array2d(surface) + :noindex: + + Creates a 2D array *(integer pixel values)* that is copied from any type of surface. + +.. function:: pixels3d(surface) + :noindex: + + Creates a 3D array *(RGB pixel values)* that reference the original surface data. + This will only work on 24-bit and 32-bit surfaces that have RGB or BGR formatting. + +.. function:: array3d(surface) + :noindex: + + Creates a 3D array *(RGB pixel values)* that is copied from any type of surface. + +Here is a small chart that might better illustrate what types of functions +should be used on which surfaces. As you can see, both the arrayXD functions +will work with any type of surface. + +.. csv-table:: + :class: matrix + :header: , "32-bit", "24-bit", "16-bit", "8-bit(c-map)" + :widths: 15, 15, 15, 15, 15 + :stub-columns: 1 + + "pixel2d", "yes", , "yes", "yes" + "array2d", "yes", "yes", "yes", "yes" + "pixel3d", "yes", "yes", , + "array3d", "yes", "yes", "yes", "yes" + + +Examples +-------- + + +With this information, we are equipped to start trying things with surface +arrays. The following are short little demonstrations that create a NumPy +array and display them in pygame. These different tests are found in the +*arraydemo.py* example. There is a simple function named *surfdemo_show* +that displays an array on the screen. + +.. container:: examples + + .. container:: example + + .. image:: surfarray_allblack.png + :alt: allblack + + :: + + allblack = N.zeros((128, 128)) + surfdemo_show(allblack, 'allblack') + + Our first example creates an all black array. Whenever you need + to create a new numeric array of a specific size, it is best to use the + ``zeros`` function. Here we create a 2D array of all zeros and display + it. + + .. container:: break + + .. + + .. container:: example + + .. image:: surfarray_striped.png + :alt: striped + + :: + + striped = N.zeros((128, 128, 3)) + striped[:] = (255, 0, 0) + striped[:,::3] = (0, 255, 255) + surfdemo_show(striped, 'striped') + + Here we are dealing with a 3D array. We start by creating an all red image. + Then we slice out every third row and assign it to a blue/green color. As you + can see, we can treat the 3D arrays almost exactly the same as 2D arrays, just + be sure to assign them 3 values instead of a single mapped integer. + + .. container:: break + + .. + + .. container:: example + + .. image:: surfarray_rgbarray.png + :alt: rgbarray + + :: + + imgsurface = pygame.image.load('surfarray.png') + rgbarray = surfarray.array3d(imgsurface) + surfdemo_show(rgbarray, 'rgbarray') + + Here we load an image with the image module, then convert it to a 3D + array of integer RGB color elements. An RGB copy of a surface always + has the colors arranged as a[r,c,0] for the red component, + a[r,c,1] for the green component, and a[r,c,2] for blue. This can then + be used without caring how the pixels of the actual surface are configured, + unlike a 2D array which is a copy of the :meth:`mapped ` + (raw) surface pixels. We will use this image in the rest of the samples. + + .. container:: break + + .. + + .. container:: example + + .. image:: surfarray_flipped.png + :alt: flipped + + :: + + flipped = rgbarray[:,::-1] + surfdemo_show(flipped, 'flipped') + + Here we flip the image vertically. All we need to do is take the original + image array and slice it using a negative increment. + + .. container:: break + + .. + + .. container:: example + + .. image:: surfarray_scaledown.png + :alt: scaledown + + :: + + scaledown = rgbarray[::2,::2] + surfdemo_show(scaledown, 'scaledown') + + Based on the last example, scaling an image down is pretty logical. We just + slice out all the pixels using an increment of 2 vertically and horizontally. + + .. container:: break + + .. + + + .. container:: example + + .. image:: surfarray_scaleup.png + :alt: scaleup + + :: + + shape = rgbarray.shape + scaleup = N.zeros((shape[0]*2, shape[1]*2, shape[2])) + scaleup[::2,::2,:] = rgbarray + scaleup[1::2,::2,:] = rgbarray + scaleup[:,1::2] = scaleup[:,::2] + surfdemo_show(scaleup, 'scaleup') + + Scaling the image up is a little more work, but is similar to the previous + scaling down, we do it all with slicing. First we create an array that is + double the size of our original. First we copy the original array into every + other pixel of the new array. Then we do it again for every other pixel doing + the odd columns. At this point we have the image scaled properly going across, + but every other row is black, so we simply need to copy each row to the one + underneath it. Then we have an image doubled in size. + + .. container:: break + + .. + + + .. container:: example + + .. image:: surfarray_redimg.png + :alt: redimg + + :: + + redimg = N.array(rgbarray) + redimg[:,:,1:] = 0 + surfdemo_show(redimg, 'redimg') + + Now we are using 3D arrays to change the colors. Here we + set all the values in green and blue to zero. + This leaves us with just the red channel. + + .. container:: break + + .. + + + .. container:: example + + .. image:: surfarray_soften.png + :alt: soften + + :: + + factor = N.array((8,), N.int32) + soften = N.array(rgbarray, N.int32) + soften[1:,:] += rgbarray[:-1,:] * factor + soften[:-1,:] += rgbarray[1:,:] * factor + soften[:,1:] += rgbarray[:,:-1] * factor + soften[:,:-1] += rgbarray[:,1:] * factor + soften //= 33 + surfdemo_show(soften, 'soften') + + Here we perform a 3x3 convolution filter that will soften our image. + It looks like a lot of steps here, but what we are doing is shifting + the image 1 pixel in each direction and adding them all together (with some + multiplication for weighting). Then average all the values. It's no Gaussian, + but it's fast. One point with NumPy arrays, the precision of arithmetic + operations is determined by the array with the largest data type. + So if factor was not declared as a 1 element array of type numpy.int32, + the multiplications would be performed using numpy.int8, the 8 bit integer + type of each rgbarray element. This will cause value truncation. The soften + array must also be declared to have a larger integer size than rgbarray to + avoid truncation. + + .. container:: break + + .. + + + .. container:: example + + .. image:: surfarray_xfade.png + :alt: xfade + + :: + + src = N.array(rgbarray) + dest = N.zeros(rgbarray.shape) + dest[:] = 20, 50, 100 + diff = (dest - src) * 0.50 + xfade = src + diff.astype(N.uint) + surfdemo_show(xfade, 'xfade') + + Lastly, we are cross fading between the original image and a solid bluish + image. Not exciting, but the dest image could be anything, and changing the 0.50 + multiplier will let you choose any step in a linear crossfade between two images. + + .. container:: break + + .. + +Hopefully by this point you are starting to see how surfarray can be used to +perform special effects and transformations that are only possible at the pixel +level. At the very least, you can use the surfarray to do a lot of Surface.set_at() +Surface.get_at() type operations very quickly. But don't think you are finished +yet, there is still much to learn. + + +Surface Locking +--------------- + +Like the rest of pygame, surfarray will lock any Surfaces it needs to +automatically when accessing pixel data. There is one extra thing to be aware +of though. When creating the *pixel* arrays, the original surface will +be locked during the lifetime of that pixel array. This is important to remember. +Be sure to *"del"* the pixel array or let it go out of scope +*(ie, when the function returns, etc)*. + +Also be aware that you really don't want to be doing much *(if any)* +direct pixel access on hardware surfaces *(HWSURFACE)*. This is because +the actual surface data lives on the graphics card, and transferring pixel +changes over the PCI/AGP bus is not fast. + + +Transparency +------------ + +The surfarray module has several methods for accessing a Surface's alpha/colorkey +values. None of the alpha functions are affected by overall transparency of a +Surface, just the pixel alpha values. Here's the list of those functions. + +.. function:: pixels_alpha(surface) + :noindex: + + Creates a 2D array *(integer pixel values)* that references the original + surface alpha data. + This will only work on 32-bit images with an 8-bit alpha component. + +.. function:: array_alpha(surface) + :noindex: + + Creates a 2D array *(integer pixel values)* that is copied from any + type of surface. + If the surface has no alpha values, + the array will be fully opaque values *(255)*. + +.. function:: array_colorkey(surface) + :noindex: + + Creates a 2D array *(integer pixel values)* that is set to transparent + *(0)* wherever that pixel color matches the Surface colorkey. + + +Other Surfarray Functions +------------------------- + +There are only a few other functions available in surfarray. You can get a better +list with more documentation on the +:mod:`surfarray reference page `. +There is one very useful function though. + +.. function:: surfarray.blit_array(surface, array) + :noindex: + + This will transfer any type of 2D or 3D surface array onto a Surface + of the same dimensions. + This surfarray blit will generally be faster than assigning an array to a + referenced pixel array. + Still, it should not be as fast as normal Surface blitting, + since those are very optimized. + + +More Advanced NumPy +------------------- + +There's a couple last things you should know about NumPy arrays. When dealing +with very large arrays, like the kind that are 640x480 big, there are some extra +things you should be careful about. Mainly, while using the operators like + and +* on the arrays makes them easy to use, it is also very expensive on big arrays. +These operators must make new temporary copies of the array, that are then +usually copied into another array. This can get very time consuming. Fortunately, +all the NumPy operators come with special functions that can perform the +operation *"in place"*. For example, you would want to replace +``screen[:] = screen + brightmap`` with the much faster +``add(screen, brightmap, screen)``. +Anyway, you'll want to read up on the NumPy UFunc +documentation for more about this. +It is important when dealing with the arrays. + +Another thing to be aware of when working with NumPy arrays is the datatype +of the array. Some of the arrays (especially the mapped pixel type) often return +arrays with an unsigned 8-bit value. These arrays will easily overflow if you are +not careful. NumPy will use the same coercion that you find in C programs, so +mixing an operation with 8-bit numbers and 32-bit numbers will give a result as +32-bit numbers. You can convert the datatype of an array, but definitely be +aware of what types of arrays you have, if NumPy gets in a situation where +precision would be ruined, it will raise an exception. + +Lastly, be aware that when assigning values into the 3D arrays, they must be +between 0 and 255, or you will get some undefined truncating. + + +Graduation +---------- + +Well there you have it. My quick primer on Numeric Python and surfarray. +Hopefully now you see what is possible, and even if you never use them for +yourself, you do not have to be afraid when you see code that does. Look into +the vgrade example for more numeric array action. There are also some *"flame"* +demos floating around that use surfarray to create a realtime fire effect. + +Best of all, try some things on your own. Take it slow at first and build up, +I've seen some great things with surfarray already like radial gradients and +more. Good Luck. diff --git a/docs/tut/camera_average.jpg b/docs/tut/camera_average.jpg new file mode 100644 index 0000000000000000000000000000000000000000..043e485bd7a025a23890bc78891a76b86583f758 GIT binary patch literal 20881 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 _!Kbf7RWO_Ay9$&+hsp}+V$vU4C z(6x7{%K5^AKDZysvo6ZcyJWWq=n18rhdY#Hf3;Qjv#C+?U z`BI}SgcNKq(z@wo>YODT=_htvCgBH8+A$0=6$oSp*;f>KPFa`+2e}>p07_#`hQJQT z>;C}Oq(VP6 z;3iM8uF7~-9g(zR$yf)@dHge)f68O~kH@LTDyxtV&__LZ&+?@*Ze4_t`qs-0b43=3 z%SMBtKIfW68D5Hi3{)*B0|nUqXjW`w9=-8eEI8739=patP~L`~H)k>IC)tHWj?tX% z&(@r`3>%yu$NvDWMCl}i+vrQ>yAjxW8nGJf0g8Zqt2u6xHY5jcpeCh;TdBE@&Tp>L zD~ha?H)eC@wx)`ZNF#QA&lM?rF9(s=ip>^Uuo*GO5FO7IEOzopM*D_rc8uhj;&|F| zcDczpM|+w^P)GzXJvpbv9Fso9QghqAXz5F*!60VSu4F#0LXQ6c<6F^Rq;5Q`dnv5x-KzIT<$WDVbM{{X6; zJg*su_}e+8=PtJw>{oKHmmpZvoSfiy^!iokd_TT6Hy07fpGM=qx6-LgJF@3)J@;af zZYJQDB!9hL&J%}uHJUMSt#5VM*hnob4pKOsy>q)Af5wN@803SHf7!+>EZws8IX;-p zK_&0Xc_Ti8zMBh|Vc@kyEG(q&Eln$%?Z9QSDhV!8*B$E|+-0y155E-gFx~#JpQ*2E z7DI7{DAHNg@w9R5X&kFCWsC#sRFYL0%MZ?+XFU{y>FHJM?XbO#o`u69IU{aI jr9xSV&PU(zC^}L?@pXYv_=X$@c`?~MXb?pr7 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 literal 0 HcmV?d00001 diff --git a/docs/tut/camera_green.jpg b/docs/tut/camera_green.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24c4b09b7a34b8ac8fddc0805e4d33935420016a GIT binary patch literal 10219 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 Ip$|Xy9|&cGng9R* literal 0 HcmV?d00001 diff --git a/docs/tut/camera_hsv.jpg b/docs/tut/camera_hsv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..afe95597a550a2bfb234caf2cfbe610493507890 GIT binary patch literal 36673 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 literal 0 HcmV?d00001 diff --git a/docs/tut/camera_mask.jpg b/docs/tut/camera_mask.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd8ed1deb4f210bba9f0a17bf755b8452966fec8 GIT binary patch literal 18779 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

3I44^ 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 H`O*IY`E>=u literal 0 HcmV?d00001

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 literal 0 HcmV?d00001 diff --git a/docs/tut/chimp.py.rst b/docs/tut/chimp.py.rst new file mode 100644 index 0000000..6ee3815 --- /dev/null +++ b/docs/tut/chimp.py.rst @@ -0,0 +1,8 @@ +.. include:: common.txt + +**************************** + pygame/examples/chimp.py +**************************** + +.. literalinclude:: ../../../examples/chimp.py + :language: python diff --git a/docs/tut/chimpshot.gif b/docs/tut/chimpshot.gif new file mode 100644 index 0000000000000000000000000000000000000000..c27191d1cf58b123e313c47fb0f6640aaf8de0af GIT binary patch literal 46010 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 LCL@ed0FVCxQs}HF literal 0 HcmV?d00001 diff --git a/docs/tut/intro_blade.jpg b/docs/tut/intro_blade.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ed490cb9ed61f98b5ede5105e034afeaf02b986 GIT binary patch literal 2631 zcmb7Ec{tQtAODSIkWuz^j6M6V!CT8tz!#@3w}yM#OL`#$ge`~95robPj<&pDs-eLmmsb9O%Md<7)E+&$d^5C{Z# z@CUFn3b+8GV6X^SSX4wrL`+O{4@6c1A}$V5l9t>E#L9Q&omS)wNA@)isT@pin() zeIqk-D=RBCU0Vkm3wskwD~nwbkeHYlL>!_hA)#oY0oAbhzp?WtASDVE0Ivi=nt*^5 zNKgv2(*>vifFNjh{tJ+RppYnkjH=xb<lxJR+n6vb6qx7D3DSy}lM-o>uo#!R`aWDix&9=x?p zd61IB$WB7o^t#3PYUUnXv&<|Tdc6a5u(N-e^GQ5g_=6OCM<3PM+aA^IjyX|vXK^Y< za|v;mT=W2uoRPV<1CT8HsV*# z>&Ve5Z}O+4k!3@a&E%FEGpj1#41(jw^gqMH~S$RX{@Bqa|C4)x)N|@25>Y30W*M$2Mz&H2KX_|ql73#6e36he}V@p8h>NB`V|^nca?IcGUbFF zZ&6%id|ysj!Y;7+it7M6Kvtlb zTA?RK8JNKd>@I%!`syAyNr+wvQQ9%cQP|4c{r3KJ%gBP9Af4jsnSfyDVoeg*b?f^t+lasT7c)dYJC%9w`nHCJEJv|f0jvS_@XHn2){!VUwGyls9D`cQ5 zdvj3FQ$nKz<0PhTa78>aAd+D$C*|6Jb&fRLf89Mtj0%|v;BO!>hoLc@-UN>-D+=1G z#Z6ejnVL~doxutD%~Yv^WMu;ivrm-FYGtpW-`k^Z z(M>zhQ-cv;McjYGP1`Dc*9UNpG~-c5MP(yOno%Rxr4qrgI>++Pl)JMh=X_SA(m=)F zwMZqdY?XP!El-{3ww~L#FFM23_SUa3mD3lGq?o)+-?-br%X#MYrbcpt!?Os=G(yB$ z3QU%8P@DHxAvcGAA)JeuIDmcVKtG_^gpA?B=$!_kRhJB(=7*Zxc(^w>h)FI-8hm(s z;C#y=H+08?!-b#g+plulVaF3q=GVj5+vsJf_K#KKmnKqO{CISu)(XTuTCeG;xvfoT z4f5LFBBT27TzIAF#7Vj#OfifO#j|LNi=GM%dB?s7#v+DsL}fRwa%P$I%|X-18BL6` zn>HrXbwI&UCK~F>I_pfODM&@bDbe6h0~I4(WNDL6T=}7+l1y;0n|q6!(|K0ZiVg0V zPLX|Md%{{Q1E!Y!t)8dqb+4EvYVh09Q}f@?-@6P)`AWuNwjL-n8jiQvZ-)embx=z< zBPIC6h$3Ib+2y!ji63vTzKc+9*wE>pPqpi!Pq`U8H6gIc5g z(M~?hqA4YQFa693M(M`QN4c@HUzBi+aSx1S;)iPe`xM@uWL(bdrxO$((_uCh9R~R! zq?er|>>`2@wrt_Wy%%JcpCvKALCIM_3PR6&3QEN2xx(`s6%wBD-5I5wg0H6B&h^%Y;|PkYacwez`O@xgO^ zXc?P!=tl1Hnge&m*0-CjiXG@#J5m%@V4b%?#Bk8w!)&^N|LiMH_&cJ7-y;7zZ=1G0 z`fLGb=vi4~*DWzubfNjOL%h@bH@5TD(uF#TA!`MUp}AK7?QVXJ>0+i!(>oHFM>4VWf5X*hfK`v zY(-c4?so_{)p$E5EzQ^a>lX3}*l3`Ca=~RHyHvh5aK0{R#awBBv{V_FVCebGbb2$z z_@83J zCS>#Cnp(0$^`q1tE$5D}g>7Mn)KbeU@VR2M6OUL+op;}a#l=MF59ect(((qs)q5YW ze)F(lis?-aA@^dCHQgGeUw`fkDFQ?BCyGC|D>oy(xo2K;(CMBq=+g&83bkAdL%X#_(GE?ShR4@})ys zzU?-RFx~W^Qx)CFB;Drjlu@$ptFFo4=MILBFwI?Nu+O-l~5`p^ul#b5ZA$-?hjFGxHm?R-z2 zUTq-ke)N!O<`8`ch&+BO_xfyH*8?O+gR4hRdgaov25Ih_#XaR1r$MK74E(<$szzzIOz(YhXVwQ0l}S-zX5)QxC{UQ literal 0 HcmV?d00001 diff --git a/docs/tut/intro_freedom.jpg b/docs/tut/intro_freedom.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ed473d5c507edce6ef4729a965ba86a6bee1198 GIT binary patch literal 7050 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 I3x1scALv*^8~^|S literal 0 HcmV?d00001 diff --git a/docs/tut/newbieguide.rst b/docs/tut/newbieguide.rst new file mode 100644 index 0000000..93bc457 --- /dev/null +++ b/docs/tut/newbieguide.rst @@ -0,0 +1,494 @@ +.. TUTORIAL: David Clark's Newbie Guide To Pygame + +.. include:: common.txt + +************************** + Newbie Guide to Pygame +************************** + +.. title:: A Newbie Guide to pygame + + +A Newbie Guide to pygame +======================== + +or **Things I learned by trial and error so you don't have to,** + +or **How I learned to stop worrying and love the blit.** + +Pygame_ is a python wrapper for SDL_, written by Pete Shinners. What this +means is that, using pygame, you can write games or other multimedia +applications in Python that will run unaltered on any of SDL's supported +platforms (Windows, Linux, Mac, and others). + +Pygame may be easy to learn, but the world of graphics programming can be +pretty confusing to the newcomer. I wrote this to try to distill the practical +knowledge I've gained over the past year or so of working with pygame, and its +predecessor, PySDL. I've tried to rank these suggestions in order of +importance, but how relevant any particular hint is will depend on your own +background and the details of your project. + + +Get comfortable working in Python. +---------------------------------- + +The most important thing is to feel confident using python. Learning something +as potentially complicated as graphics programming will be a real chore if +you're also unfamiliar with the language you're using. Write a few sizable +non-graphical programs in python -- parse some text files, write a guessing +game or a journal-entry program or something. Get comfortable with string and +list manipulation -- know how to split, slice and combine strings and lists. +Know how ``import`` works -- try writing a program that is spread across +several source files. Write your own functions, and practice manipulating +numbers and characters; know how to convert between the two. Get to the point +where the syntax for using lists and dictionaries is second-nature -- you don't +want to have to run to the documentation every time you need to slice a list or +sort a set of keys. Get comfortable using file paths -- this will come in handy +later when you start loading assets and creating save files. + +Resist the temptation to ask for direct help online when +you run into trouble. Instead, fire up the interpreter and play with the +problem for a few hours, or use print statements and debugging tools to find out +what's going wrong in your code. Get into the habit of looking things up in the +official `Python documentation`_, and Googling error messages to figure out what +they mean. + +This may sound incredibly dull, but the confidence you'll gain through your +familiarity with python will work wonders when it comes time to write your +game. The time you spend making python code second-nature will be nothing +compared to the time you'll save when you're writing real code. + + +Recognize which parts of pygame you really need. +------------------------------------------------ + +Looking at the jumble of classes at the top of the pygame documentation index +may be confusing. The important thing is to realize that you can do a great +deal with only a tiny subset of functions. Many classes you'll probably never +use -- in a year, I haven't touched the ``Channel``, ``Joystick``, ``cursors``, +``surfarray`` or ``version`` functions. + + +Know what a surface is. +----------------------- + +The most important part of pygame is the surface. Just think of a surface as a +blank piece of paper. You can do a lot of things with a surface -- you can +draw lines on it, fill parts of it with color, copy images to and from it, and +set or read individual pixel colors on it. A surface can be any size (within +reason) and you can have as many of them as you like (again, within reason). +One surface is special -- the one you create with +:func:`pygame.display.set_mode()`. This 'display surface' represents the screen; +whatever you do to it will appear on the user's screen. + +So how do you create surfaces? As mentioned above, you create the special +'display surface' with ``pygame.display.set_mode()``. You can create a surface +that contains an image by using :func:`pygame.image.load()`, or you can make a surface +that contains text with :func:`pygame.font.Font.render()`. You can even create a surface that +contains nothing at all with :func:`pygame.Surface()`. + +Most of the surface functions are not critical. Just learn :meth:`.Surface.blit()`, +:meth:`.Surface.fill()`, :meth:`.Surface.set_at()` and :meth:`.Surface.get_at()`, and you'll be fine. + + +Use Surface.convert(). +---------------------- + +When I first read the documentation for :meth:`.Surface.convert()`, I didn't think +it was something I had to worry about. 'I only use PNGs, therefore everything I +do will be in the same format. So I don't need ``convert()``';. It turns out I +was very, very wrong. + +The 'format' that ``convert()`` refers to isn't the *file* format (i.e. PNG, +JPEG, GIF), it's what's called the 'pixel format'. This refers to the +particular way that a surface records individual colors in a specific pixel. +If the surface format isn't the same as the display format, SDL will have to +convert it on-the-fly for every blit -- a fairly time-consuming process. Don't +worry too much about the explanation; just note that ``convert()`` is necessary +if you want to get any kind of speed out of your blits. + +How do you use convert? Just call it after creating a surface with the +:func:`.image.load()` function. Instead of just doing:: + + surface = pygame.image.load('foo.png') + +Do:: + + surface = pygame.image.load('foo.png').convert() + +It's that easy. You just need to call it once per surface, when you load an +image off the disk. You'll be pleased with the results; I see about a 6x +increase in blitting speed by calling ``convert()``. + +The only times you don't want to use ``convert()`` is when you really need to +have absolute control over an image's internal format -- say you were writing +an image conversion program or something, and you needed to ensure that the +output file had the same pixel format as the input file. If you're writing a +game, you need speed. Use ``convert()``. + + +Be wary of outdated, obsolete, and optional advice. +--------------------------------------------------- + +Pygame has been around since the early 2000s, and a lot has changed since then -- +both within the framework itself and within the broader computing landscape as a +whole. Make sure to check the dates on materials you read (including this guide!), +and take older advice with a grain of salt. Here are some common things that +stick out to me: + +**Dirty Rects & performance 'tricks'** + +When you read older bits of pygame documentation or guides online, you may see +some emphasis on only updating portions of the screen that are dirty, for the +sake of performance (in this context, "dirty" means the region has changed since +the previous frame was drawn). + +Generally this entails calling :func:`pygame.display.update()` (with a list of +rects) instead of :func:`pygame.display.flip()`, not having scrolling backgrounds, +or even not filling the screen with a background color every frame because pygame +supposedly can't handle it. Some of pygame's API is designed to support this +paradigm as well (e.g. :func:`pygame.sprite.RenderUpdates`), which made a lot of +sense in the early years of pygame. + +In the present day (2022) though, most modest desktop computers are powerful enough to +refresh the entire display once per frame at 60 FPS and beyond. You can have a moving +camera, or dynamic backgrounds and your game should run totally fine at 60 FPS. CPUs are +more powerful nowadays, and you can use ``display.flip()`` without fear. + +That being said there are still some times when this old technique is still useful +for squeezing out a few extra FPS. For example, with a single screen game like +an Asteroids or Space Invaders. Here is the rough process for how it works: + +Instead of updating the whole screen every frame, only the parts that changed since +the last frame are updated. You do this by keeping track of those rectangles in a list, +then calling ``update(the_dirty_rectangles)`` at the end of the frame. In detail +for a moving sprite: + + * Blit a piece of the background over the sprite's current location, erasing it. + * Append the sprite's current location rectangle to a list called dirty_rects. + * Move the sprite. + * Draw the sprite at its new location. + * Append the sprite's new location to my dirty_rects list. + * Call ``display.update(dirty_rects)`` + +Even though this technique is not required for making performant 2D games with +modern CPUs, it is still useful to be aware of. There are also still plenty of other ways +to accidentally tank your game's performance with poorly optimized rendering logic. +For example, even on modern hardware it's probably too slow to call ``set_at`` once per pixel +on the display surface. Being mindful of performance is still something you'll have to +do. + +There just aren't that many 'one neat trick to fix your code performance' tips. Every game +is different and there are different problems and different algorithms to solve them +efficiently in each type of game. Pretty much every time your 2D game code is failing to hit a +reasonable frame rate the underlying cause turns out to be bad algorithm or a misunderstanding +of fundamental game design patterns. + +If you are having performance problems, first make sure you aren't loading files repeatedly in your +game loop, then use one of the many options for profiling your code to find out what is taking up the +most time. Once you are armed with at least some knowledge on why your game is slow, try asking the +internet (via google), or the pygame community if they've got some better algorithms to help you out. + +**HWSURFACE and DOUBLEBUF** + +The HWSURFACE :func:`.display.set_mode()` flag does nothing in pygame versions 2.0.0 and +later (you can check the docs if you don't believe me)! There's no reason to +use it anymore. Even in pygame 1, its effect is pretty nuanced and +generally misunderstood by most pygame users. It was never a magic speed-up +flag, unfortunately. + +DOUBLEBUF still has some use, but is also not a magic speed up flag. + +**The Sprite class** + +You don't need to use the built-in :class:`.Sprite` or :class:`.Group` classes +if you don't want to. In a lot of tutorials, it may seem like ``Sprite`` is the +fundamental "GameObject" of pygame, from which all other objects must derive, +but in reality it's pretty much just a wrapper around a ``Rect`` and a +``Surface``, with some additional convenience methods. You may find it +more intuitive (and fun) to write your game's core logic and classes from +scratch. + + +There is NO rule six. +--------------------- + + +Don't get distracted by side issues. +------------------------------------ + +Sometimes, new game programmers spend too much time worrying about issues that +aren't really critical to their game's success. The desire to get secondary +issues 'right' is understandable, but early in the process of creating a game, +you cannot even know what the important questions are, let alone what answers +you should choose. The result can be a lot of needless prevarication. + +For example, consider the question of how to organize your graphics files. +Should each frame have its own graphics file, or each sprite? Perhaps all the +graphics should be zipped up into one archive? A great deal of time has been +wasted on a lot of projects, asking these questions on mailing lists, debating +the answers, profiling, etc, etc. This is a secondary issue; any time spent +discussing it should have been spent coding the actual game. + +The insight here is that it is far better to have a 'pretty good' solution that +was actually implemented, than a perfect solution that you never got around to +writing. + + +Rects are your friends. +----------------------- + +Pete Shinners' wrapper may have cool alpha effects and fast blitting speeds, +but I have to admit my favorite part of pygame is the lowly :class:`.Rect` class. +A rect is simply a rectangle -- defined only by the position of its top left +corner, its width, and its height. Many pygame functions take rects as +arguments, and they also take 'rectstyles', a sequence that has the same values +as a rect. So if I need a rectangle that defines the area between 10, 20 and +40, 50, I can do any of the following:: + + rect = pygame.Rect(10, 20, 30, 30) + rect = pygame.Rect((10, 20, 30, 30)) + rect = pygame.Rect((10, 20), (30, 30)) + rect = (10, 20, 30, 30) + rect = ((10, 20, 30, 30)) + +If you use any of the first three versions, however, you get access to Rect's +utility functions. These include functions to move, shrink and inflate rects, +find the union of two rects, and a variety of collision-detection functions. + +For example, suppose I'd like to get a list of all the sprites that contain a +point (x, y) -- maybe the player clicked there, or maybe that's the current +location of a bullet. It's simple if each sprite has a .rect member -- I just +do:: + + sprites_clicked = [sprite for sprite in all_my_sprites_list if sprite.rect.collidepoint(x, y)] + +Rects have no other relation to surfaces or graphics functions, other than the +fact that you can use them as arguments. You can also use them in places that +have nothing to do with graphics, but still need to be defined as rectangles. +Every project I discover a few new places to use rects where I never thought +I'd need them. + + +Don't bother with pixel-perfect collision detection. +---------------------------------------------------- + +So you've got your sprites moving around, and you need to know whether or not +they're bumping into one another. It's tempting to write something like the +following: + + * Check to see if the rects are in collision. If they aren't, ignore them. + * For each pixel in the overlapping area, see if the corresponding pixels from both sprites are opaque. If so, there's a collision. + +There are other ways to do this, with ANDing sprite masks and so on, but any +way you do it in pygame, it's probably going to be too slow. For most games, +it's probably better just to do 'sub-rect collision' -- create a rect for each +sprite that's a little smaller than the actual image, and use that for +collisions instead. It will be much faster, and in most cases the player won't +notice the imprecision. + + +Managing the event subsystem. +----------------------------- + +Pygame's event system is kind of tricky. There are actually two different ways +to find out what an input device (keyboard, mouse or joystick) is doing. + +The first is by directly checking the state of the device. You do this by +calling, say, :func:`pygame.mouse.get_pos()` or :func:`pygame.key.get_pressed()`. +This will tell you the state of that device *at the moment you call the +function.* + +The second method uses the SDL event queue. This queue is a list of events -- +events are added to the list as they're detected, and they're deleted from the +queue as they're read off. + +There are advantages and disadvantages to each system. State-checking (system +1) gives you precision -- you know exactly when a given input was made -- if +``mouse.get_pressed([0])`` is 1, that means that the left mouse button is +down *right at this moment*. The event queue merely reports that the +mouse was down at some time in the past; if you check the queue fairly often, +that can be ok, but if you're delayed from checking it by other code, input +latency can grow. Another advantage of the state-checking system is that it +detects "chording" easily; that is, several states at the same time. If you +want to know whether the ``t`` and ``f`` keys are down at the same time, just +check:: + + if key.get_pressed[K_t] and key.get_pressed[K_f]: + print("Yup!") + +In the queue system, however, each keypress arrives in the queue as a +completely separate event, so you'd need to remember that the ``t`` key was +down, and hadn't come up yet, while checking for the ``f`` key. A little more +complicated. + +The state system has one great weakness, however. It only reports what the +state of the device is at the moment it's called; if the user hits a mouse +button then releases it just before a call to ``mouse.get_pressed()``, the +mouse button will return 0 -- ``get_pressed()`` missed the mouse button press +completely. The two events, ``MOUSEBUTTONDOWN`` and ``MOUSEBUTTONUP``, will +still be sitting in the event queue, however, waiting to be retrieved and +processed. + +The lesson is: choose the system that meets your requirements. If you don't +have much going on in your loop -- say you're just sitting in a ``while True`` +loop, waiting for input, use ``get_pressed()`` or another state function; the +latency will be lower. On the other hand, if every keypress is crucial, but +latency isn't as important -- say your user is typing something in an editbox, +use the event queue. Some key presses may be slightly late, but at least you'll +get them all. + +A note about ``event.poll()`` vs. ``wait()`` -- ``poll()`` may seem better, +since it doesn't block your program from doing anything while it's waiting for +input -- ``wait()`` suspends the program until an event is received. +However, ``poll()`` will consume 100% of available CPU time while it runs, +and it will fill the event queue with ``NOEVENTS``. Use ``set_blocked()`` to +select just those event types you're interested in -- your queue will be much +more manageable. + +Another note about the event queue -- even if you don't want to use it, you must +still clear it periodically because it's still going to be filling up with events +in the background as the user presses keys and mouses over the window. On Windows, +if your game goes too long without clearing the queue, the operating system will +think it has frozen and show a "The application is not responding" message. +Iterating over ``event.get()`` or simply calling ``event.clear()`` once per frame +will avoid this. + + +Colorkey vs. Alpha. +------------------- + +There's a lot of confusion around these two techniques, and much of it comes +from the terminology used. + +'Colorkey blitting' involves telling pygame that all pixels of a certain color +in a certain image are transparent instead of whatever color they happen to be. +These transparent pixels are not blitted when the rest of the image is blitted, +and so don't obscure the background. This is how we make sprites that aren't +rectangular in shape. Simply call :meth:`.Surface.set_colorkey()`, and pass in +an RGB tuple -- say (0,0,0). This would make every pixel in the source image +transparent instead of black. + +'Alpha' is different, and it comes in two flavors. 'Image alpha' applies to the +whole image, and is probably what you want. Properly known as 'translucency', +alpha causes each pixel in the source image to be only *partially* opaque. +For example, if you set a surface's alpha to 192 and then blitted it onto a +background, 3/4 of each pixel's color would come from the source image, and 1/4 +from the background. Alpha is measured from 255 to 0, where 0 is completely +transparent, and 255 is completely opaque. Note that colorkey and alpha +blitting can be combined -- this produces an image that is fully transparent in +some spots, and semi-transparent in others. + +'Per-pixel alpha' is the other flavor of alpha, and it's more complicated. +Basically, each pixel in the source image has its own alpha value, from 0 to +255. Each pixel, therefore, can have a different opacity when blitted onto a +background. This type of alpha can't be mixed with colorkey blitting, +and it overrides per-image alpha. Per-pixel alpha is rarely used in +games, and to use it you have to save your source image in a graphic +editor with a special *alpha channel*. It's complicated -- don't use it +yet. + + +Software architecture, design patterns, and games. +-------------------------------------------------- + +You may reach a point where you're comfortable writing code, you're able to solve +complex problems without assistance, you understand how to use most of pygame's +modules, and yet, as you work on larger projects they always seem to get messier +and harder to maintain as time goes on. This can manifest in many ways -- for +example, fixing bugs in one place might always seem to create new bugs elsewhere, +figuring out *where* code should go might become a challenge, adding new +things might frequently require you to rewrite many other things, and so on. +Finally, you decide to cut your losses and start fresh on something new. + +This is a common issue and it can be frustrating -- on the one hand, your +programming skills are improving, and yet you aren't able to finish the games +you start due to somewhat nebulous organizational problems. + +This brings us to the concept of software architecture and design patterns. You +may be familiar with pygame's "standard" base template (there are many equivalent +variations of this, so don't stress about the small details too much):: + + import pygame + + pygame.init() + + screen = pygame.display.set_mode((1280,720)) + + clock = pygame.time.Clock() + + while True: + # Process player inputs. + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + raise SystemExit + + # Do logical updates here. + # ... + + screen.fill("purple") # Fill the display with a solid color + + # Render the graphics here. + # ... + + pygame.display.flip() # Refresh on-screen display + clock.tick(60) # wait until next frame (at 60 FPS) + +It does some initial setup, starts a loop, and then proceeds to repeatedly +collect input, handle the game's logic, and draw the current frame forever until +the program ends. The update, render, wait loop shown here is actually a design +pattern that serves as the skeleton of most games -- it's prolific because it's +clean, it's organized, and it works. (There's also an important but easy-to-miss +design feature here in the form of a strict division between the game's logic +and rendering routines. This decision alone prevents a whole category of potential +bugs related to objects updating and rendering concurrently, which is nice). + +It turns out that there are many design patterns like this that are used frequently +in games and in software development at large. For a great resource on this +specifically for games, I highly recommend `Game Programming Patterns`_, a short +free, e-book on the topic. It covers a bunch of useful patterns and concrete situations +where you might want to employ them. It won't instantly make you a better coder, +but learning some theory about software architecture can go a long way towards +helping you escape plateaus and tackle larger projects more confidently. + + +Do things the pythony way. +-------------------------- + +A final note (this isn't the least important one; it just comes at the end). +Pygame is a pretty lightweight wrapper around SDL, which is in turn a pretty +lightweight wrapper around your native OS graphics calls. Chances are pretty +good that if your code is still slow, and you've done the things I've mentioned +above, then the problem lies in the way you're addressing your data in python. +Certain idioms are just going to be slow in python no matter what you do. +Luckily, python is a very clear language -- if a piece of code looks awkward or +unwieldy, chances are its speed can be improved, too. Read over `Why Pygame is +Slow`_ for some deeper insight into why pygame might be considered slower than +other frameworks/engines, and what that actually means in practice. +And if you're truly stumped by performance problems, profilers like cProfile_ +(or SnakeViz_, a visualizer for cProfile) can help identify bottlenecks (they'll +tell you which parts of the code are taking the longest to execute). That said, +premature optimisation is the root of all evil; if it's already fast enough, +don't torture the code trying to make it faster. If it's fast enough, let it +be :) + + +There you go. Now you know practically everything I know about using pygame. +Now, go write that game! + +---- + +*David Clark is an avid pygame user and the editor of the Pygame Code +Repository, a showcase for community-submitted python game code. He is also +the author of Twitch, an entirely average pygame arcade game.* + +*This guide was substantially updated in 2022.* + +.. _Pygame: https://www.pygame.org/ +.. _SDL: http://libsdl.org +.. _Python documentation: https://docs.python.org/3/ +.. _Game Programming Patterns: https://gameprogrammingpatterns.com/contents.html +.. _Why Pygame is Slow: https://blubberquark.tumblr.com/post/630054903238262784/why-pygame-is-slow +.. _cProfile: https://docs.python.org/3/library/profile.html +.. _SnakeViz: https://jiffyclub.github.io/snakeviz/ \ No newline at end of file diff --git a/docs/tut/surfarray.png b/docs/tut/surfarray.png new file mode 100644 index 0000000000000000000000000000000000000000..8c5c918fa91a6ce6102b018dd7b13667f8291407 GIT binary patch literal 50836 zcmV)$K#sqOP)2vD>b- zGWB8KYT$*=hl=isu3M+~&Xt)zletL82G&9dq%d@Uoc!6vjon}Q`=9@nf7!qCR8`e~ z{`J57Prvs6`Od4~_}C|(dG47TS0-bQ0Um7=>bg}W1^4@XLp+mAXxBaXiV>A{Z zuc|KT8{;5a*2St`r~NEwEk>D9wDrz~i>uSBcu@au|MmZ1#~bgz@#=5=?r;3|AO6n& z=70F_|M{=}v-e+r^EZC|zr1z#Ug@I|>wPdpJ~V^8mt{%Wlyy@%f}xm^l5kkzf<^;e&fCsW&#ZfAqyK+_?4eYSsQf|K0!NKmXT%^WXjJ zfAPQi`CobGtqc)d3|v_tIB0!>G0^@)>e;=JpIfw%naD8m#-Wj9WZ0HTD2x@ zUfD5e@2%JFy#Bqn@4bI#d0PIT|BwIsXI{8ondBb_tHxQ& zfF%wHqLlR~YHZ%`oh?_1%L8eex<^Nkt59=l$Y5(Sy^wAtn)>qhpT4m--85u+gWM*mh%~jI&*!87NR*&lR4XW_XhNNl=X9n9t@su-D?zxt0ZT-ty7>6?$w&M;p&K~yRw zutFqwPnMZgqQs^y;aF8{nhHTxkB?_(XJ>hy6R^9zwY|MPpP#PRYh#RILqU=>dGf^! zGl$m0FcB?Q%NXNqHtUZ^P1}++P2IM>CZoM9cg~>+XR{MxZJOrMqen$u8Dlm!#^cdo zbviS~n1qJIp&(dh!yE<7GM}FrV-~A9n1sf1mR!)g&@6=SsQ+o~ke!Js!uCtdeh=V?Dp)+cAGn&|cF+aQuVU-g@VQ+l%#TRhK5A&CT&M&)&Fr zVXxQgt58|i%XLMtAw}>++j_{jFdBkN>Hz=fC(%Kf_iZ9i2{hHX0uj9+orF zV3@3uL=I#Ltd@-9L{(#qAq30Du`$GnP3xlc-fv8&r}LBAw>uZM09h|qZQcI#Pk!l( zU;N_huYLcwe(yiC)yvl|?(J?53Ddfs)O8Qa3}#kDRe{Fs&5d53#^@)Tqbt`gUA=zk z;PCYE!xJLo>n1n&g`fRWYMu9Qiw=|!kU$@UB3@Xd`s(9J)LY%`jZR$*A~mQun{&v#1J&b*lI5w92_1-#M+0V zsLp1^VqV3-{oXi6olZAH)EJ{8)^)jBEhDt?rBa|E^|~^gA04lc&x-l7S*)wJ4MkCu z#Y%#gw)R!Qq=ukI+%Rpj(DcJuGMo3;C&T4@RL+N``9GutB3KI|D3;FL9wdWjpLN5j zhqLLhYCRcP=WLqPbzLmiv(r-_MG3~RwKjEbI2bvb5SiX!v|6s)DBg$ldNmjfqYvwH zWvuBB^6jmSt)0zlH=n+7|`0ee)!&p7j`#)>6d?D z>%#Q@gS(F(K1_@y(Wa_LgP~)SCN57im1vBEvQ3;1p$VR>saqcb7&TE@+r*9l0|wAb&~ZMCY4K-jx< znUm!8*WdlxU;g!*ue`Otv)@bepZd}ldxO;VEQqSInjM~GE;pPwmrh0_%g))1jmxuM z5FzHK^)S}QNK8HkV@=&QUZOZ{LY1dkhQxSRtm1Ost_x|@M5Q)*VkL?(6szUwVs=th ztFkF-YKpX8ZPvw8%~@|5GqfBUxklb6nOm&N^lYvnN(hFOSxMq# znE6m%y0$%-P8y-b(V|(FP8nXWUcT~EU;K&v%e%)%2g}(!Ptw#n2j+f1gtn@smrvWa zO`HQjhU>b{2K`l06;<7MPsYv`b1{@9iFn=|Z};-S!-tO}hxKv}q4|9A+FNg2+rQ#{ zvoRiM+&nrt13Mp>VjH76%RaV7Od}ycU7DBP7mHQ1ZYJq??N+JbU;S_XS(E5P=AWA<(E48J++; zo6Whgl=syI0ZqqyFFc?1ImujpeD=7k=Jy{RCP{Mj;)N{BE?>T!W?9}Fuse*c-<)jB zPEMEeMV2Mb*xA|In7!d>Qa3(G2pS@(O;Yu7k_|Xu(BLZWH z+4j=jvWnI*TNT5K=*#x!n$LV|+GS zjgC)_j!xRDUauA^F;6M)*-JZ@P0utE7PFewLRgwO?hRi4J0HLD)MeOsc=)(jEDf=U z1d+*j?3miR2B4|{M8qXY8)6%ToN1eet!Y94QC&CAxl8+3=O?Sv=1$Z4d9`rP5>Xp` z8-1jZI*OrY);zVPZ&H`Eu>}AkA40XBkGD75)!GB0YKwL2YnqOC%R#-reKD%o{;*!j z*`j{)wfByXPm9G0!1WtfFYNAI-oLOh8Zo0sq6`5lA3}^m#MZJRf(Sdb%M`Xou5b!?a! zO5$TQhKUeDAR^|(+GJgCCn8D7oS zF8XnnnCZs2*IO)RZPh2 z%hV-?*|Cx6TVH3rfiXr^t+f)tY@JI?N=4JQ5^a)}ZL=&?n?FrLg8Wm%NV zS(#_!`FwHX`U_XDJy$gR_A77w?GjH=bJxx>==`wz4h$P&;HO$&)vGw z&kS4VLsYU+R0PTlLooq?tz`;m8?D!2y{4j+)A^#PtFkOZXnm*!KJTT8>zl+8vCVBZ zOiX5yoX!$)8EisIFkpeIDjTv;?eHLo03xCoc(rVnX?@n#>VT$!C6_vvyK1%WTXXI5 zb%82jHqU1B!}mVC8)NMCde7W^YBHQoMx%POna|hF*oP2S%d@Izl2L!MF|tYGqlPxt zr8i(zy>MZV8EU1i8}Wfe6Pt8+keP^CqYx318e_nOCPJBQ0&uf#L*cJI{ZtH?FINu^ z9<`wj5_^Ne;o;%>$}({M@X`J4$<}mZv{)`lE!4-%EP_ln`Y`EWqaTS6502XghMWES zK*bbg>szgh5E|lWc6Tma-nsPF+aG@I*T3=FJ8v~>Af~_wNCEC*tBvi^e0}`QcfS3- zcRv3kFaD!{@bkUgf+<8vl7td&)SJvP2>`AAYF382T`gp}(38_e9UC7iVj+aQXM6qe z#^xmJr@dZg5-=mlxsir4lV=t&C`6(+oETzJ5fKYx&f{Da5CONI7R%DDij|d2D{Md^xZf))`8f?(XlP&xID{>5AHz80*-ihV#kTvSCo_95X{m*{D)f6`-wKH3DaY z_eEV)P1&P9i?N!rLm8Hhug{jJHP!hjwT=hMxCZSz?48N7l5T2?+($EbDgeedP`gmu<^Ui&ok?lr}*xPbQ;{ zUOyR+N0Y5lk{M%B)vM69Rk2T*!Da2|hqL1} zUs)HMplnRydV_vZRhEKOW<1I@V%Qt)O!pXMj9Dy>9v`3i_AO)F3(uKBZ?Jc9ON{zZ z#?W)g)Z~(+DX~499W57yrG#SmWB6->;M;A7(RJE+?;$(ItCJLJ2Mn6eR>Zta$N{FE?50>k4=9~+a4?$LSS^By+ z83btA#-^5XQTr#~4MGR0RkS zQ4&>v$WYbPRa2XkFJ9b#?y2WVdq?woE=@{b1!+9BR>_fN(>-`SJ3G^eC{ottdcE}C zhv1We8ye=+Wm#{rTr{O$&1zJKPQSwYM3!QJvuo(D2tVE%5_=RNqds6WDo%XL|F+0QYKi4 zf&gYH0ZK$o8y4&0s3_}xuO$kg#JP336oNBaq*Pa<7=t2aF3;0JKWju}xi~#Moxk$N z8&T!v^=pQCV>62~G%nZ@K^vQ9v)OV!TUVt=#Hc^KdhPPwmFc`Z3r%a)Ix;CI(UP@B zBA_sAlmId!k|bHvwxut~YM!|H@odBF)RivQ^GC;zA3VG*&Li`^ev+_(dSx|^nyRv( zv(v^oSC&QA%UwS=P6N?uS&3l~4WIsNQ+U-`fL<~z{CKm4P=eEE|vUcb4=DFVf~ z6kgl2hs&yvRU3+kD%7bpY2tS`N0aSIZ=CJyY&LCGtQPBHS+Ca1#cX+YeDL^T<`RN3 zn<|kLI>u9DBBLZARtgFLuuugIm;izbfS^)^wl%aUTTkRwhS{L;tQLtgsY#BHkFB*t zFqSNtEbDn`z4ukUIygC%*I#R6+t1QLzgN^n=?hq*XzM1<&Q>Q!XR$`HC_nMs$EKUZ zS#esoMN_r8?IkveQB&ufbCek4QV}VtT0{U+MVh83t0wCwxy^>@gxmDscAmekU4L#=)8+>z4xK2L|c$pOH5TWuiFOJ zIA^SkEKx7b3?o+FrPh$`rF~|QCEpY$^Tj(KygwfH^EB;9PM7q0!^wPE%uW_{;r&W? zwsxPsb#=NoI9e`32&u7-I7?CkGAt1Fp^Y(u*;y^n|+RO8pWxmm1WcCegKhS5s6VnVuY%yL=EEG5XiExD-~N;mG;#n zZqVxm+PHD!sj^xv*NeKS%Cblur6%9s-s%qqZCRC}nM@{C+YX0AKlgdRH|z~bXfa!? zm*sj|i-N^WG%2u2V~+v77EqTn1|isaC}t>f3sKbbNU9_@r$^ z>aw2eC%trYXzRLC)htcLwi}aanSK&HL#vWwlUihr=N= zD{B+H_a0H1QMEqdfHX*3|ZNzN*_MOVZ3G`CtfN!wiabD;|S%P}lz2 zwQJM8;i{g85SpqTxPD?yYE3WCMFK$x224?<@&Qr793_@@kxo($Y$!iHSr>J4TFjQk ziAlY6d0DJ_#z2%~kQfHNoCUpJzifT0QDS7u!ESc4Xe+7aja0gtueLX)x1PV1jhq|1 z+OM0Uf{z+V5`v+&X}VK48jVPmnOlijuRmX}phhGH6;;&^PdjTY35(Qml=oTb^z`)b zs4PP4jR()%e3ltmmfd~ue%Z{+a{c}Xw~1&n99+40>E!WgTeb!?7z~b2kDJE#`$G|s zSlId8IRoLQj@DQoW0nqGLaNg1 zS$A>tC|P&xBdJ2c%tGgZ#hp+HsH&!!8SHM-$Zq5*v*`~9L`2R+hWM6!Y^!>`T=n~X zjpDs$NZFJcLt<=jy)^69RS`nl2Gh3UdMUxI*41KJmg{DDws_{svrpf=I@#H{e|USn zDEn#85P?LrjgiwNsj3z#&ZSIbp+Tc@_G~_9$GN&uI?2t>{YQ5X&yJS$3Awi4%h-$Y zh#``CYuF?yltU0A>i2WDMh$!KTi+JzRw_y;tJ-F>KYjY<4Lj!Eb{5d6k5acrEm;cC zAZ>_EZZqGs%NSI3b9<|9n|dv5OZM$3+4}k`X%R3i_c95mR z!$)@( z-2xO@g~bq21Oc!h01D~83n{BhFr1`*n)L@+nr6ohWY1-h)aE!6>m0Fz)CfByFtme(p$!uK~v-PQPG3}?0gcVS72BfB`>tr-+ zMTDRRqEX4Iu)?etD_@3s;gitIO!Dl_>%(y#)7YT)b;Y9E24`#}C^ShDqXGd5L+gKNa!VLEPdI8yUimB`D!&!`gPLlXPH*@GD*z!D>sOg zp(5eG- zr*c`t8#Jn|RO@2NpHSQ}#ogOTNwK`K!# zvnAiwurNKR9D6QZ9xqRhXWEcT@+g%3!A=Mqi^ta5!7u}&!ds`qet&a3X`5Q3Jh*@G zJ^PApSEF8kYi~F&Pb}HqaAfoJcy>ZToa*+*#-NuU9v%TBVDr+YPbWN-i0AK1NRB*ok{=7{^h0$r;B;nmg{<6l#6tbR3WN~X_n?D z%dFY#544SB(>7?9CsottL+_h*aW*4GnkA|}!h=GRC#IKFJa1|tSSTxT_s&_xo(qNa zge67vzS3$vkMq#>+O|DAJ8OIm>zasSwUG5nW6XNJ(PS&{jSmm!@4S8Iop&GBD?lwY z1u|d=Sin5_70?KX0s%3^x}N*fc?C4L-~WTJ{KeOP?n|HlvCn<-*{3cec#R?gW-eE2 zPF?HkR@$;DH%HSOH=ae~j+)}Z;r*l8qjV_N3?(+XbD^o6VG*&;d1!!&268M)W$mK} zf(s2|BMynl+}76ibaQ0;+~3SADvGK#5e&z+vy}+|ilnMUob`L4wiCjewoPmzA|a}< za>DG4u|@^utiJ#LquufLq9|8oy{^h6i^_%>Y}B5zb?h9cnQ7XkstyMuAM2uwho@(Q z2lpm}zHh~5xo;{?-0AG>(Zhq2qtldomo8uU;LiOh037)8#`IZ2rV1hz6$TS|b`4`i ze0F;J?)`_~Sg+r!$_Ky+a7L&c@T>+txf4PJ}{t=0J1a>(k40US&PE=bZKmk&aK*<6O1)_inM2WG^ zTAOA)4jZs>gGHiA$?!~41ghMi+SwaxIdgK z94W`x*45mHrAP@`0xMtz%oWR{qt(CvpMU>rU;V}}{`^n>%uj!wIf(b1I3cV00f3^ab}3gxjNu3iZ~#SC4~e7!p^cHOaY1Ajq=7GU z8#eCUTdj+_tiy6$rM(iYieN2gxg%0*?QoPUT2K)6X_~g$1GRS^Ji2^g-=-OSoo2(+ zMbS2)DVxb?b2Te3UAgiXU;k?bfUG~fo~M_hH=s`TjR06$=2cO>`R=>FetPm9=rK?L z9`K;Ril6(bAN~Aif5fCIlBBKA>Sh^Y$;ML*&X_2Tb2%cI4LB{zHnd)poJqB5qEM8k z=g7yXP>&dcMB(UTslL`0@m!Br2!V(QL>4Mw17Z*$G5Vk(I^toPU)tNR>$a*Y9=O(r zst%cvQj&)c4?g_x_+$npKzhIs7^d0f3;Vaye9zjALH}ab-y+JPsR{#3EKw>&9b@5} zwQ5nU@132zcY69x2#+Eb@7+85H~;R}l<>1(`mt<~R*hGp);Eo>yTWwi>a&mU9v`2b zJ~()IJU_}tb~s8&gG!8m7yx9fZ6&f{VHjhAsIz%lg-}Lm)T*sl%_tpgZA|;4)Z2zK zs(l-)*t2OFI{?VUO2kCU1XZ<`MZ|(clnpa$AW;@!b=I*-hgpB1+2OsDyLXO{&(>G8Jz-?~a41NT$M2M~C2ZIb00MV$f=bTG>{T@iFqO2<~MyCz>m*~5E>XJ@PX4eP5i1Hq@ycWuBOB6 zbhcCgNT(Y&R0o!OBIv43q-eQm{o|&52Ur2&#TT#t=#PA|KX6yBT%2xBM#)BfR`*jw z*3_{s+O={NkSZa1h3jW|$|j(RF?#PCRMzrvJTSa&tGX;#RlAB-S_Pa5!Xd)9G1iDA zRa;hrQi8-7yB4d<`cK>qq_B+0opGH(S(caTvwj~oaiXS?!1k~H;!j_D^&XUgNemm~ z&6l2i=1ZHCA12)s>4%tyNFdXJ6r({^eP9D(hS2$gP#{Klf$FBQ+qYiWn(pnr^VV;L z^&6}D>_7b4Z(qG}{o5>*08mo1sc_x?C)Z#j2jyvQ9HI9A>>d_eB9E>bNB9 z+8ENr3X@AR;w;aT)$D9FFWO2daF)0$7cOjX4o$9_N3l_2^c>M?emx$HL%zyul_by+(6r-++^1{XI zq{I2?^7!=R;PfGqkh0-4cc8YYt#D|)_r5GD072tq%IV1UdcC5E^I2I}adx&E4W`Ta zVq<5rxiL(KM$^_?6%qErLZV8B5tYCIQwL>Kp&-CoB36x&tPulc(`akhIC3PK>rjGO zu8X2+U|3mgij6^kILNY``#lh zTCSRTb$Yry0xPj`BtF!w=jg>!+fTF3Wm(m$5JKm%8}<8vr9xcCXp%g5Ez24qhB`(s z+QgNtXiB}_K(!@>egpxTEJR_u5uNUVvMQ-+miCh9LsMIqW&Ppr{P7=t`y1bb_Msco z&Cg!H`VYqAPx*EnBqx)K1Z#{U5J3e*FoZ4_;0deG3<5<65f~aYN&u0Ku@A|%rk~o{ ze*Wb6QN;4Q-}}L*f9U!CAh~+!#;~_hEkjZI)8$DMOXkoYq)B2OE48h(VYOT}wJ(Yy z%`@i=kx5);tyPuPs+`Z3b=h(##>4U6&L&wAhhU+lQ;t^>ZnMZ>pAB)h5erp7nc) zajb2*3S^jcww#X!J)0P>6hzj(iH0f-aLy|?wTBpA`OwCC)x@f;sCL^)zYpN7iz+2i zLf2y%=#!{|0mw&P%vV0kU7q!Nwy44@uf6}rU;Zl8K{nms3om}`U#8|+l?k&;Z6X9B zLl#hks9+I+1f@W#>Ln5>v1&KfMWm_;(;!P!r4Fh@#Kzjm&h85*$KM5-5AWQ4e0(sC zgIk*~rrdA14dk0pyPVTJ>GiE4mW$~-UdT};euNI5h;^5$HUHZC-i&b5$W7{Ch z%x6CL$)EhYpG|WU1DLI9V?f>q5h)A*u`hmdG}<~koKegm7H}j6FvLc>B0vfO2@!K@ z`_2u#XA%6yum3)?7Huh!_9pu;JpabcO(inyLomh)B57nMV@P8F zgp5~2!%jd-1Z7oKm2QrTi9&?2HbzV~E&_dk+5jJ#r=R-N-uC6wqgB&XhsTeLY8ibs za_Pt#~=8+$vO*)S<$UB?(g z>tIEN*)ox36M`6<2{8bhki^znHi{_0THD4}NR_DxO`0e08iIEwB~FVfG*N=0XzQYG z%DT1@Bj2qzWvtQZ-3#7pMLteo9pEg zQJr;3f*4oZI~VRfIR1k_{XZQZog5x50S6=m3$;%yzkL(qw;r;kiJghjc|(w@yTxP&74s`Ryn zB1)@<5>j$Vl;Y0*&i>PvPV)sbg9(5@&)F*``%zWwzNCy!W1vQ%Itaobw!}71bzY z3=u>)amli&fCxk;hL}v^ph}4~iK{~_3m?kRuDmp{Exj=YK{HBs z_O>@SrtD}m9k37}o%0b-zMVY}YqF_@8nMqug)!AZobTT_IY{#SB(P(!t*iUR}^y0Ki;Y!X01XzRMJL*d(EV>sI1y5Q^xeYtb@WU;KIyf>R_^^*aw9 ztEN#INC1C)c>DX`eP=qM`yV{|OJ@z;*eykZJ$*zBpB*FL|oF@5m( zwFh^;F8ZLU=70I;-`?8T+TGdkUgu})AH4qV>1id}2X=uBFhE8;9S&Y38md0g$ev^@ zg;PwPdg_bbUw28V>Omq(1X(XneRFhj@~Xyz^?LD*Z+-jf^`8d|M`cD+)unHoGkGsz zX0O8FEX!=-qLK&@L1K(V9~r_Bqdp`_y1lt&a*nCyqg+>AH~;{Hlt@)AAm{1oNw@)s zF|^XA{r;=p_}=NVhUUQ58UXDt9y6v{KetpKLj3uVn zl}AkS-f%e1T^}kG!tv2^z2Jj~Z~WjpZ`}UyVcozvj7QnkE4x4Pg-pO2p>DqukfPip#vO4_wtAG97SHJWV zU-*?@{@Gs7fXS-}sNc^Q)k-6|EdRg$oB#2D{$$7C|urF6`|8!qYc?W;A>{1as?|pV}CI`n`AlZC!ugSL<(n>-&HI zmws;0&%gThSC3Ctz<|?h!{HC_Y`&Bw8>7LVb7Sjv+b|_`jt2fnjTKmHcQ0P}qH0Op z7|S9-1O%oFYWVo}?caItz5fdO@Pqds96vhR-ycWcHo+URY!cs=#6m<(l+?Mj-|r8G z^JQ7A>SEb8%R09M-$WDbq&J*yji(!v;bw2CMd&GPj2e^`0Fn8~gk_)PRY6zPfS`gH zo5mll=dXPKO~e#5GLsvVjaw3@5-jVJxqNgoqu8YK{{F$?_uqT(58C!k;1HODijM?H z0Dx=i_nW$Zax?)(;N5m2AMq``Wwwc-kmdQtWOHM* zA#*uCK79Y3*WP^VLA3@X1tx$AZLCk$$0v8+`rzJYKKt^EpLl*btC}+O^8S_W%@QrGone&MxO-~9Lg-~UjD4A=&Cr(2)6bn#>TbaP$I%Ie;od*6!Tb{o%r z|4;tvFTeKfRjI%xaP8?^zkK!bFG8Y9vjFp_|dCiqulCqZmF)Q|A;U0YH?@*v#leM4}fFVX{QrHj<qm82y!FPr8~u+NimT;ZgQjVk_iXBtNNm`%b8KBv`C{F)RrIBgtrD>|81{NQ zTiaXH4V#-_LvNfn!*JTny!g(J1wGex09Y`6L|=iRKva>oZECk(wX?G|Vh){Lz5Ge0 zQE1s^(1?ycWCQO*V%x@l`0o4v;qc*K0w=%{C_%;cg^g#QzM^d-Ar|ZQ_-J-?vIN$G zr6PsgD^|8x86W~RP=cGS?c`tni+^q=mL*s4Np4+|4u_Ndy^E`5`N6x#?|*Or z0>lBkz!c~Mh2k(`zFah4{_^)8+&_BZ`CAgrs#raL_2yuh)+W>vHG(5zQ0KC*|M^#6 zfAgWj0=vXN{QUEOZ@h6$lo9I1?Cslkey?ucP@MkppMB${mtVMfW6z~YH7692WVG! z&P`9MYOSh7uf)uNF>Ht^MtD(*7P>te-CD1|L4pS#9@Nj@$}-K9+-qp68p>(kkxLSn zS(iqoqNuCdw^eA$U^PMDzUys{H^-9^Wm+U9^|asbw^G$@5jB9jDKCN$8K|m-3efpj zJGy~YRf0;u$dFUo+Z#cXr(Ggiv7(!=?i4n#H;?ob_{nNvTzYp9aG!F5`vsZrl zXMgN7pL;2WvYO2e84bK%myaJmK0Td%@cxG%-hQ}P&MOZgSO-xI2IhqqpZ~&-e&*`M z3-jYywN8_q1Nowk{eGGz{n2o9F@NoY_YZ&+Iso=AUiyiPmtIcO@qB);oV|JX-Zz0q zi1T;edEk&+F&)$+^uJ4uYBhi5U2oGZanp?moNRakC&r#;~@a4H3Z4i?9%4et<%FF09Y(m zRn^qq16eP-nx&V6A4DWj>V{p2x{()j1nJ-Kgn+8DVMKI8d;%C1W)3k@MC$T1>2*HR zrfE`_tyd?|#i*+{ zRa=nRGLwX&UaiWqwwxCEXi)olwE{C%MfsU~<#^a164jd3qKcWGiw@Y*@BcF9z6CQ zK$hi~$K$8H9{?G_h9F=UBWp;vwqClMU#Y7*WfAV(yZ8L3uGLN1%!;k?_-wuiARz4z z_7XddlF^ekGAg0~A#?W9<;y=cJGp!9sTVI@{uzUAXPUjg*U`qe$oJPh!Nhy8ALhPGXNNdDoNMx3Wz8~an?dTGZ_lj)iEA4^#h;< zaO3(FR;jASHw6)FLTr0rvUwVntFo>Oznm2*G8i89hJ$`Sp7hd@jV^>NlA+*(Zv(Z4 z4N)Xku<}Q_Q&gWc@5+D$Ggw4@8z~0zL09X#djQs?q*h}jLbM1$4UwMH=zcM~2P}ZF zwKe|OC!QZ}_SJ?mtm}2<>&Rl7#)m2f<2N=EAKPVFSr-RM5;<7rMX_`_yM(1O#Yzs( z)@O^FgutQpo`{;J98Ja#9y|aT=x6!$t<9H%-&RQsgABw21VfYQ_$8M<@0&wF7OS)2 z#vtq4w#NE++15?QP6UK-@7|s6B#nm`6EkURA~Gu0FxnW2p~2?)bTrtjtBkogI5@D@ z#u$w{1LthgwW!?;oG4hK3MMGQSTKyrXgqxB`H%hY#v2pCKHwyPL=BSyqDmA+1L;}W zzEiB<1{x4P^}{bY=fFU0SL=ICdypkJA+QEf5Cho2e)I+jiu0PNP$m+AWiZHE@&W>w zVx9%!+3D#kMfon!jECu^i~B}3cS*6ByNqhDV;c1aJ(K6hC(CBtRO`U7)+WAc_jk6h zUfrcMhO9xNmN~XjL?|%DPGIgrysOiHQ<^QvKnWsH1tL*qZDJE=(}dlV{|Sw%kr^SJ z|8Wr|B4QE|5O>8pLMPi(HB1h5(=?6ujSmryjZ5>YSS=Q7W4LZww9zZT6oRObkCF_A ztFnId=xkPn*=l8pB}R}jhNAdD{&aQ*7{F~zFJ<%Q((0sX z8c)oK^pOnuQM1DeA;bW7WZcGd^HW5s>QoUzu*_`}Y|2bU#452xQ@`{2>%R@X3l#eo zH(vhqi|h4zFwWLz72^Hlqwid~aw%~aeZyodb(;n#579AM0z^TKsA8C6^ahpalBj|j zL!LQAsaijKeDK{nw|@sXaU8d{ryHYTwLT4A>bh=JM``XQq-olCY3guxvS^Bsn0||P zZ*Ob=!q#xBSIWw3OAHp0IzY&>H6T*9=Q;InVydG;Ei{4+U_jJO=`^ihS5*a}ZV`>f zx>*IkBHkg5?2S_rf?6E=4wslr5{0@nY%{a5H7+Dn%i1@MZ(B>8CV;Z{ADuI1w&H~im=PnGjEEQpGYc$W zRH3S@sGF7@C$?{G((#jZU5bQ{!mIl-B4CTCkO+by0#pDs#;B-CDC!(Iis8yvUmi-cxf z4adFFc#tH?a#q&spsh%wVq|B3Z*ybRA1BAvu^kww5%1M21#o9KHtLLJWP%v`1*qGq4xTKl zQe8D&mTH>DursFfaYRK>^&){f8S`9t;EwAXjV322*04Q%bQrx@wM`if_xCSe7APQ1 zRm2#TROx(Xn&^DKuM0J2C`2ftHNj8|Du|b7CvV+<^zE~=A0WI99H*vK3P1i6KlFtk z|KXxsK>Vja_2S(R{;-Jw@y_E1#p4IxadzJa1!lkq?!_Pdk$;i8F+3|nLL?$*Nu*sZ zKRiACGvFS;KmZz`0Y$Jtu{llu-p_sMx#zAI>p2-)HEn-5C=ORu)ns{}$rS7M`0+_o z%VM^=vO6C4d()kv8*=WlCbrr{^<*Lpvr*HL9mW`I%-?RX{&pz@pdbMmkcdc(K{Yx@ zn;S!G5TrtVZ&lps_n(c5gc1L?{wcj)`qDEu+wXnvfdWwvkB{{Uf+#JgEUXlUar(l z*Sg*92@nDA!%ENqAV!xjw8N?dQ65h=&yESe;pth?RFDRMA)A=Qz&dt~Z!TZi2i^u` zxjGC|xXjdRpFx;8gwERo73uXyfC-{?-4^rm+J#Hu#I`=PO=RW{yZlXW(H&QT3YAp?~$?{c}!2wJJhc{`luUm67?+ zzy8OovH%1)^Wpt-y#(8koy4>fYmoslj4`AdH88;%0p`Fd$Uqec9r`pDPu<-8`@iyc zfB5AWs&!#lW>JG^lDI7GrAZ%@0O~*$zmzqKWnHXVX=!g~@8;DjyE|iKvE(wU#1LX5 zR*eN4Qtmbs85Kl*lA`|qdaVEDM^!;WtQy0hmv0RF$7eP8?BL+_r=Iz7imHY>iBrG~ zfn+|~jmgWO`SgE#=guD;9e)!t1FEKIKDb@nx&0dOiZhsO^rzGD_RhwYOZyitT-d*~ zn@sw~>bN(mmd$c;7B%*U*<`b~vo}mLR%z>cu{t_g7VFh&WoTdx0Rn`oTpRGylCa})t9evn_hAjIKIvA`FawH<+#SnAXc2ZD;5L#n0B8sBSBoPFVu|87QgBoKv zvedAyw^%mbdyTR4nKG#egrR_CfZ!MsU<_h}0Srer$E)>QcW;0B=`xfi zukQWgFaO==UwUdZNteqrUseb{GyKIb{P1MF^;h5c?g#JRUagi2h@urhU1DmLH8>cD z5T$dwGLetsr3E}lhU4@Xf8p#{b+OopSy@(d)? z>D0Kitm@f(B~fQ5%l&8eMjKgwBW+#ng9n%bjIdRHGAjW95+NcY(gjv0i=Y29b?%0a z4~YT;W4bm_ds*+&*5umN)8n%bfYYPLuU@!#`6Xx#<*qA~KW)Pv?k<>G1eyJk+MD znTVMQq4lk`gARf~pJ-cTVpI_USoK_nu*|_LzzQ<#Qj=H9x}R;;p{SbDI>e@fcYoW? z*!|ZaLQupQU1DN9ST6tcmGA!t4exb{O5ry~>CMX*FHSdp?&rVcCP~_(s$BZE_Ej0H zKqgodU;4!Ln@?@8m#d~}RLm>if9t>e{$D9HhElXKq!K}3D9DmBNif#-085PNbo#IV z^}kA!~3vOmaAe#lksRcNKekNwL6U}4-O8`&gO09 zFYaIZ#3w#Jy^sX1gkoqsS~5yjjR6_zW&=bChL~UgQq_;l7M|)3VvHfk zVzH=Y;Mu+K{LMGs|DY^as2(1lzP`V+Pq-LcwkbkD1RO&Jk<%Er7^CrIe>{Hf##2AK zT79^h-7eOrUYhy(SlUNG4MZRWU(L^&`Rx8{Ke+ox|Me?ZE?;=z$cPZsoqFy8b>_ZdU#-`m9{HS?F zx5y`TP?%wR&BFNIiA-aK7XAOF&In$rxCN$+2O&##l8KD7cZ`=r)$4> ze02YV+aF%o+1%Qi?(S~YWf`0L=yY}Y#-)6i7j?T>tW>FKn!W2=y-~)wdheUErT_=a zLWy-ELPX5W%t8@rosG8J>e;=8PUs_&bGo5>9?U?uQPVQBNCf%)3)@dUb>Y?59)RZ$ zAN={n{bvxzM5Cq!JHSH#d*1fipbW8WdM?}ANT1)F`tB!|)oi)GyI9;^oZek7ZvzLw z8T1TTud4XwyLaCG@XkvwKlii0@cAh1>ER(n)Z2c4qwX=HO1t(PtFmBlgi7=v!4p!l z>*9&f+25=^FYYl$-*~mKWMDgC!4r{+@AneJ2r>Fl_)wAx1EeHRejqcLl0kn1ND;AK z*TvdzO*SK+MUKPC&?W4BkXW^CZ4wb?>P9sg5$MV^uok)d{)b;)uipUXAbI(d*Kb_A zGS2%{$EU7d8gCE03u!NlPJcbqgLv?$2y;U=$;3w!Wc6e z4|J5r$)G>!|HPMm^vyf}DXbP)zH;~8A3uL}qH@WYK@e*VT93p)B$8n!BWhwqj44A& z!D0Zid~LdMb7!mMoAbJPv|QaS>j#Giudn7G0!u~d!~B(3-tnk^{PUmO80{sj(z-0| zw>iZaW6Rd^>6~zOLI^&T!Pkz_bsh>Z5IeC9F3$!Xv3+(@%}!=L8X%}Kl-Pt2jkQfJ zlgY?AG*N;tnzqOiQaP_@{A8d+0K+NZ022dL*(E7kUd>OvZ;T-z0IkBGE5jf0&H^$W zx73I}IzIdkFefxmJ-zqR$6xSOSuAGP_b*L1`)&y888y*2O>6@zthEqjJ{Or2>-zn^ zh6qE>8D<~~AW*Lzjiy3Mmcc|&j@>{Q(6;T-(b2fyH&)5;?(T*8a^Zb*IzM^y-S-e; z>XLP{QVW-*^JO_ZUaV*JFzdhg;)@$weKl=WRZZRI(XkK|1dRfh*ls;6kt!zyV{%vJ z!Kv#)s#_e}MVmcux|q>fN@0j-FzDOuQ5g3*ORtQ^KlJHOeB;l50DJ%N{okb0KmW|H zM7^nT1mmnj)NYB+lftAh-I-MtfpJhJ#Bq>5@gzwv?j|n*_4Ug|Q9nF8dF%F_KX0mU zg>d-&@7`IRtiJG>=P&GU?QUIceAwQ~s;Y9fw_Mk|dwlod3Dn0}d0!>DkT5Hl5ar2w zFC>W@0uIU)CDz0dD%vr4G1v%pWcyj4xzipR(FP=-ZkDL4DZ+-k2X!88OkTKbeG}I6 z^|3&LbjTRQLL3>u6S3Yo z;CK)Uki#LzD=zAR$tdT9+kum`7vFs(tCDkG=Qa-P4D2 z$ist&e;C^4nOnb-o1Jvpcs>*0Zntz>(c=Uh0Z+kH$9^Q#NCL| zM_rcz8)7mR2CC|ui-BT@ZCi@~5Mp#_ojUbSl+F)Wr%~{^-6QI9UD(u|El$_#MVdJ} z|BF?m1w|l2P1nV%z#0+)p*=o)w_BZX{pywd?VZ?G$#CP!#S4v;ZN1po9I25|HL-5h zd&7>MJqKCJhM@)|DiYgD7%&F#0ccxkGFIwXH&L>z8p*&~3uXv|_3-$>vW&)kCY^4L z5oOTp4+f(ql#h;%i?+&KFG;eZ(Z#%~*CDaVjhk0Dru}8poXzGorn$|S7)(j#3~?KL zw*t0Xi^i}S{d6;b60DkOfAva;R~Pr<3Id* zaa;iRPL6+fz53w#Q$N1B@rg9OrZOcA11xY(hlzzz>W*0I5W77Q3L^kPo^;$*>lB;$ z@G~F#`1t*IFC8EJZbWl3FTVPX@BXj<=|9vMAi~hZNE0Dyn7dheBTP!d-FEsX9});f zp>Tds1QLTY9g0Cvv6hL{2PnjLgCiPMVi$`Ykk+md77!^@24nz-fL08<+4zaGQhrnFnC)06Twh83wl}nRpjzKgd+r~P!QR;{gt&$}s zvcw%eRbvbQ)fk$f%ESI(G_+;yfpT4)4K_m8y)&DRpB0fbP5XmEcj3*!3j_~R5nOcCu&1YX9vrEG8~Qjm#^%KHqZzmW@ejM?krM)nGy$$P$G1U zFmYCkysUhC{e|EUm;!F z$js-;4^+;Zp$H;Qz|J6b))R*PEX$ZG(b%?4ktXLosH%30YE{8x^K9U3-v@3y?%ccE zA0@S~ZOU6ao1@Wic{T&IZi;R}0n_>7X(hyNs$AN#I74^I2fIPu+Z<<`+rxA~I<}H{ zB28`HhSGtU!7y?@NoN#lO(IfTYeSHPU6PtC>j4cALuidL!9!JvNmcn={Y3CxMdgsG|A3SxlI#^VK^MOF*xU-uBjC*4o+>0%P2H*qUcBXVRC&%ll3F5Y5Ec%RnXHggA|JYI0GXMi4-8U2H$d-dwokH7T1XahD?RaI@(dLd5pBugQdja1$jb+KBlm#gVu`ogo%$GkdOlug-Y z*1>qTNWlFpH-^Y?=ysC0q%2Fz)YfGid@$ZHNFys$V|O_rfxBS}K)dC@rW+Cr9-)rj zu{g`B&NyaK=hC5E+}{1!AODd@j~{&Hum1YAH}Cjn-EBk){@&w&Av0XFme=5TOn zx^<&BxR@l9G@D3ps(G4^d@ZaATlP^!w4*ImNdsB?X>640uuh*)a@545c>0O~vwP;>s?#ISMJ z+S9R(Re)E7>@f{+#VerhQ?U+F~(R`)#7YD9FCuP?#9-I$-}pA zlPFuG1QJc0b7TOv)@EtaEuxXOf#D8;MuJxag@DgDzWgmJtGl%KqkC3CM668RH9KNd z;9T0zGuL;CGn+g8Bp2aIq`H26|DXM{UoO^RezZI}ncsfz&U+u;p3hE$bPLeIWY^0N z*UMM$-~HAwfAPw-ADiyHNM_H_Bx(v$>WCQqXg#Zi8|>^nw_LmeZSLNCaCCgUy*H}J z)Ky&+RrK9k7Gj8mCyI*s8x2&TQO_s5)it+p#f1Ao8g+WK9IhXc2k57D!cfmp2PPf`~Mok+mO zIA^orXj&9j6}R7izo{Obo*gu$f9lz1UU=cz>o>3UH#XRaW3GzYS_`l=@#b?kDV0@u z)>O4`Tj$acyj8SylVo|@w(P7_k|YURS5$4&G*O}gK@ph+-F_j1|K-O*07F10y^@GP zV`6NUq@Eoi9puA=txIihn&(3nQ>@F9B8Q^M$P6d>_5Gc;Zh!Uf{hj4<{oui)?|ko- zyZ0a5zV~Rc4q%mV6vJY^x;KCA8>8vRo_+2Yv+T2qeJC5SJP8Qtnhfntr_TY~z}e}{ zAI(lLK7Dbys*BRMO|+B%p#%Af08$cSh3Qljf`Ap4ZH~qPmBgqqa6)OCGs9YP#!^aA zusNQ5poKyfi`nLuiGegR(C#O60m5wZBpsk&0L$eZ2%FQ1bFQDI!+zdntfE*D!bfvX zO6SdcC!rCUZiJI9iHJx~I@Ev(=D6!0J zcs%Uy?d&o=5QMr}G4n?U?xSt2UBr@cPneO44K#)%&!lb46BOn{O%zoW^yEqi1BoDk zWs=y@dc7$sR3l5owr@fb#?#F-Dht+HJXefyr$x9?VYr~ zVg-p>vSf*^VTJd8G#FYn&M?IYBTd`DnYOM#sH)ZO? h{h$7cpB(r8^B?}fUq#I3 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 FV1gZu=Ij6f literal 0 HcmV?d00001 diff --git a/docs/tut/surfarray_allblack.png b/docs/tut/surfarray_allblack.png new file mode 100644 index 0000000000000000000000000000000000000000..80cbc35e95c54515b85571f60f1c8fed3b7bf3b2 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRdwrE}kxqAr*7p9%N($Nlo~-{v8KM Z11Uh_Km!9~vREltkEg4j%Q~loCIB*76G8w0 literal 0 HcmV?d00001 diff --git a/docs/tut/surfarray_flipped.png b/docs/tut/surfarray_flipped.png new file mode 100644 index 0000000000000000000000000000000000000000..742f4f3ae9a759040929dea0509ba4cbbc970771 GIT binary patch literal 50835 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 Ef(cSL+5i9m literal 0 HcmV?d00001 diff --git a/docs/tut/surfarray_redimg.png b/docs/tut/surfarray_redimg.png new file mode 100644 index 0000000000000000000000000000000000000000..58e9c3f68fc501908aab0631d686a89085c3a142 GIT binary patch literal 23443 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/tut/surfarray_scaleup.png b/docs/tut/surfarray_scaleup.png new file mode 100644 index 0000000000000000000000000000000000000000..ff1f15e72dbe042cc29904186d1265030b6658b9 GIT binary patch literal 67759 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 MilU}M8Okc;e-u&jXaE2J literal 0 HcmV?d00001 diff --git a/docs/tut/tom_games2.rst b/docs/tut/tom_games2.rst new file mode 100644 index 0000000..a69dff1 --- /dev/null +++ b/docs/tut/tom_games2.rst @@ -0,0 +1,135 @@ +.. include:: common.txt + +********************************* + Revision: Pygame fundamentals +********************************* + +.. role:: firstterm(emphasis) + +.. _makegames-2: + +2. Revision: Pygame fundamentals +================================ + +.. _makegames-2-1: + +2.1. The basic Pygame game +-------------------------- + +For the sake of revision, and to ensure that you are familiar with the basic structure of a Pygame program, I'll briefly run through +a basic Pygame program, which will display no more than a window with some text in it, that should, by the end, look something like +this (though of course the window decoration will probably be different on your system): + +.. image:: tom_basic.png + +The full code for this example looks like this:: + + #!/usr/bin/python + + import pygame + from pygame.locals import * + + def main(): + # Initialise screen + pygame.init() + screen = pygame.display.set_mode((150, 50)) + pygame.display.set_caption('Basic Pygame program') + + # Fill background + background = pygame.Surface(screen.get_size()) + background = background.convert() + background.fill((250, 250, 250)) + + # Display some text + font = pygame.font.Font(None, 36) + text = font.render("Hello There", 1, (10, 10, 10)) + textpos = text.get_rect() + textpos.centerx = background.get_rect().centerx + background.blit(text, textpos) + + # Blit everything to the screen + screen.blit(background, (0, 0)) + pygame.display.flip() + + # Event loop + while True: + for event in pygame.event.get(): + if event.type == QUIT: + return + + screen.blit(background, (0, 0)) + pygame.display.flip() + + + if __name__ == '__main__': main() + + +.. _makegames-2-2: + +2.2. Basic Pygame objects +------------------------- + +As you can see, the code consists of three main objects: the screen, the background, and the text. Each of these objects is created +by first calling an instance of an in-built Pygame object, and then modifying it to fit our needs. The screen is a slightly special +case, because we still modify the display through Pygame calls, rather than calling methods belonging to the screen object. But for +all other Pygame objects, we first create the object as a copy of a Pygame object, giving it some attributes, and build our game +objects from them. + +With the background, we first create a Pygame Surface object, and make it the size of the screen. We then perform the convert() +operation to convert the Surface to a single pixel format. This is more obviously necessary when we have several images and surfaces, +all of different pixel formats, which makes rendering them quite slow. By converting all the surfaces, we can drastically speed up +rendering times. Finally, we fill the background surface with white (255, 255, 255). These values are :firstterm:`RGB` (Red Green +Blue), and can be worked out from any good paint program. + +With the text, we require more than one object. First, we create a font object, which defines which font to use, and the size of the +font. Then we create a text object, by using the ``render`` method that belongs to our font object, supplying three arguments: +the text to be rendered, whether or not it should be anti-aliased (1=yes, 0=no), and the color of the text (again in RGB format). Next +we create a third text object, which gets the rectangle for the text. The easiest way to understand this is to imagine drawing a +rectangle that will surround all of the text; you can then use this rectangle to get/set the position of the text on the screen. So +in this example we get the rectangle, set its ``centerx`` attribute to be the ``centerx`` attribute of the +background (so the text's center will be the same as the background's center, i.e. the text will be centered on the screen on the x +axis). We could also set the y coordinate, but it's not any different so I left the text at the top of the screen. As the screen is +small anyway, it didn't seem necessary. + + +.. _makegames-2-3: + +2.3. Blitting +------------- + +Now we have created our game objects, we need to actually render them. If we didn't and we ran the program, we'd just see a +blank window, and the objects would remain invisible. The term used for rendering objects is :firstterm:`blitting`, which is where +you copy the pixels belonging to said object onto the destination object. So to render the background object, you blit it onto the +screen. In this example, to make things simple, we blit the text onto the background (so the background will now have a copy of the +text on it), and then blit the background onto the screen. + +Blitting is one of the slowest operations in any game, so you need to be careful not to blit too much onto the screen in every frame. +If you have a background image, and a ball flying around the screen, then you could blit the background and then the ball in every +frame, which would cover up the ball's previous position and render the new ball, but this would be pretty slow. A better solution is +to blit the background onto the area that the ball previously occupied, which can be found by the ball's previous rectangle, and then +blitting the ball, so that you are only blitting two small areas. + + +.. _makegames-2-4: + +2.4. The event loop +------------------- + +Once you've set the game up, you need to put it into a loop so that it will continuously run until the user signals that he/she wants +to exit. So you start an open ``while`` loop, and then for each iteration of the loop, which will be each frame of the game, +update the game. The first thing is to check for any Pygame events, which will be the user hitting the keyboard, clicking a mouse +button, moving a joystick, resizing the window, or trying to close it. In this case, we simply want to watch out for for user trying +to quit the game by closing the window, in which case the game should ``return``, which will end the ``while`` loop. +Then we simply need to re-blit the background, and flip (update) the display to have everything drawn. OK, as nothing moves or happens +in this example, we don't strictly speaking need to re-blit the background in every iteration, but I put it in because when things are +moving around on the screen, you will need to do all your blitting here. + + +.. _makegames-2-5: + +2.5. Ta-da! +----------- + +And that's it - your most basic Pygame game! All games will take a form similar to this, but with lots more code for the actual game +functions themselves, which are more to do your with programming, and less guided in structure by the workings of Pygame. This is what +this tutorial is really about, and will now go onto. diff --git a/docs/tut/tom_games3.rst b/docs/tut/tom_games3.rst new file mode 100644 index 0000000..bad807e --- /dev/null +++ b/docs/tut/tom_games3.rst @@ -0,0 +1,103 @@ +.. include:: common.txt + +********************** + Kicking things off +********************** + +.. role:: citetitle(emphasis) + +.. _makegames-3: + +3. Kicking things off +===================== + +The first sections of code are relatively simple, and, once written, can usually be reused in every game you consequently make. They +will do all of the boring, generic tasks like loading modules, loading images, opening networking connections, playing music, and so +on. They will also include some simple but effective error handling, and any customisation you wish to provide on top of functions +provided by modules like ``sys`` and ``pygame``. + + +.. _makegames-3-1: + +3.1. The first lines, and loading modules +----------------------------------------- + +First off, you need to start off your game and load up your modules. It's always a good idea to set a few things straight at the top of +the main source file, such as the name of the file, what it contains, the license it is under, and any other helpful info you might +want to give those who will be looking at it. Then you can load modules, with some error checking so that Python doesn't print out +a nasty traceback, which non-programmers won't understand. The code is fairly simple, so I won't bother explaining any of it:: + + #!/usr/bin/env python + # + # Tom's Pong + # A simple pong game with realistic physics and AI + # http://tomchance.org.uk/projects/pong + # + # Released under the GNU General Public License + + VERSION = "0.4" + + try: + import sys + import random + import math + import os + import getopt + import pygame + from socket import * + from pygame.locals import * + except ImportError, err: + print(f"couldn't load module. {err}") + sys.exit(2) + + +.. _makegames-3-2: + +3.2. Resource handling functions +-------------------------------- + +In the :doc:`Line By Line Chimp ` example, the first code to be written was for loading images and sounds. As these +were totally independent of any game logic or game objects, they were written as separate functions, and were written first so +that later code could make use of them. I generally put all my code of this nature first, in their own, classless functions; these +will, generally speaking, be resource handling functions. You can of course create classes for these, so that you can group them +together, and maybe have an object with which you can control all of your resources. As with any good programming environment, it's up +to you to develop your own best practice and style. + +It's always a good idea to write your own resource handling functions, +because although Pygame has methods for opening images and sounds, and other modules will have their methods of opening other +resources, those methods can take up more than one line, they can require consistent modification by yourself, and they often don't +provide satisfactory error handling. Writing resource handling functions gives you sophisticated, reusable code, and gives you more +control over your resources. Take this example of an image loading function:: + + def load_png(name): + """ Load image and return image object""" + fullname = os.path.join("data", name) + try: + image = pygame.image.load(fullname) + if image.get_alpha() is None: + image = image.convert() + else: + image = image.convert_alpha() + except FileNotFoundError: + print(f"Cannot load image: {fullname}") + raise SystemExit + return image, image.get_rect() + +Here we make a more sophisticated image loading function than the one provided by :func:`pygame.image.load`. Note that +the first line of the function is a documentation string describing what the function does, and what object(s) it returns. The +function assumes that all of your images are in a directory called data, and so it takes the filename and creates the full pathname, +for example ``data/ball.png``, using the :citetitle:`os` module to ensure cross-platform compatibility. Then it +tries to load the image, and convert any alpha regions so you can achieve transparency, and it returns a more human-readable error +if there's a problem. Finally it returns the image object, and its :class:`rect `. + +You can make similar functions for loading any other resources, such as loading sounds. You can also make resource handling classes, +to give you more flexibility with more complex resources. For example, you could make a music class, with an ``__init__`` +function that loads the sound (perhaps borrowing from a ``load_sound()`` function), a function to pause the music, and a +function to restart. Another handy resource handling class is for network connections. Functions to open sockets, pass data with +suitable security and error checking, close sockets, finger addresses, and other network tasks, can make writing a game with network +capabilities relatively painless. + +Remember the chief task of these functions/classes is to ensure that by the time you get around to writing game object classes, +and the main loop, there's almost nothing left to do. Class inheritance can make these basic classes especially handy. Don't go +overboard though; functions which will only be used by one class should be written as part of that class, not as a global +function. diff --git a/docs/tut/tom_games4.rst b/docs/tut/tom_games4.rst new file mode 100644 index 0000000..4a4f400 --- /dev/null +++ b/docs/tut/tom_games4.rst @@ -0,0 +1,143 @@ +.. include:: common.txt + +*********************** + Game object classes +*********************** + +.. role:: firstterm(emphasis) + +.. _makegames-4: + +4. Game object classes +====================== + +Once you've loaded your modules, and written your resource handling functions, you'll want to get on to writing some game objects. +The way this is done is fairly simple, though it can seem complex at first. You write a class for each type of object in the game, +and then create an instance of those classes for the objects. You can then use those classes' methods to manipulate the objects, +giving objects some motion and interactive capabilities. So your game, in pseudo-code, will look like this:: + + #!/usr/bin/python + + # [load modules here] + + # [resource handling functions here] + + class Ball: + # [ball functions (methods) here] + # [e.g. a function to calculate new position] + # [and a function to check if it hits the side] + + def main: + # [initiate game environment here] + + # [create new object as instance of ball class] + ball = Ball() + + while True: + # [check for user input] + + # [call ball's update function] + ball.update() + +This is, of course, a very simple example, and you'd need to put in all the code, instead of those little bracketed comments. But +you should get the basic idea. You create a class, into which you put all the functions for a ball, including ``__init__``, +which would create all the ball's attributes, and ``update``, which would move the ball to its new position, before blitting +it onto the screen in this position. + +You can then create more classes for all of your other game objects, and then create instances of them so that you can handle them +easily in the ``main`` function and the main program loop. Contrast this with initiating the ball in the ``main`` +function, and then having lots of classless functions to manipulate a set ball object, and you'll hopefully see why using classes is +an advantage: It allows you to put all of the code for each object in one place; it makes using objects easier; it makes adding new +objects, and manipulating them, more flexible. Rather than adding more code for each new ball object, you could simply create new +instances of the ``Ball`` class for each new ball object. Magic! + + +.. _makegames-4-1: + +4.1. A simple ball class +------------------------ + +Here is a simple class with the functions necessary for creating a ball object that will, if the ``update`` function is called +in the main loop, move across the screen:: + + class Ball(pygame.sprite.Sprite): + """A ball that will move across the screen + Returns: ball object + Functions: update, calcnewpos + Attributes: area, vector""" + + def __init__(self, vector): + pygame.sprite.Sprite.__init__(self) + self.image, self.rect = load_png('ball.png') + screen = pygame.display.get_surface() + self.area = screen.get_rect() + self.vector = vector + + def update(self): + newpos = self.calcnewpos(self.rect,self.vector) + self.rect = newpos + + def calcnewpos(self,rect,vector): + (angle,z) = vector + (dx,dy) = (z*math.cos(angle),z*math.sin(angle)) + return rect.move(dx,dy) + +Here we have the ``Ball`` class, with an ``__init__`` function that sets the ball up, an ``update`` +function that changes the ball's rectangle to be in the new position, and a ``calcnewpos`` function to calculate the ball's +new position based on its current position, and the vector by which it is moving. I'll explain the physics in a moment. The one other +thing to note is the documentation string, which is a little bit longer this time, and explains the basics of the class. These strings +are handy not only to yourself and other programmers looking at the code, but also for tools to parse your code and document it. They +won't make much of a difference in small programs, but with large ones they're invaluable, so it's a good habit to get into. + + +.. _makegames-4-1-1: + +4.1.1. Diversion 1: Sprites +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The other reason for creating a class for each object is sprites. Each image you render in your game will be a sprite object, and so +to begin with, the class for each object should inherit the :class:`Sprite ` class. +This is a really nice feature of Python - class +inheritance. Now the ``Ball`` class has all of the functions that come with the ``Sprite`` class, and any object +instances of the ``Ball`` class will be registered by Pygame as sprites. Whereas with text and the background, which don't +move, it's OK to blit the object onto the background, Pygame handles sprite objects in a different manner, which you'll see when we +look at the whole program's code. + +Basically, you create both a ball object, and a sprite object for that ball, and you then call the ball's update function on the +sprite object, thus updating the sprite. Sprites also give you sophisticated ways of determining if two objects have collided. +Normally you might just check in the main loop to see if their rectangles overlap, but that would involve a lot of code, which would +be a waste because the ``Sprite`` class provides two functions (``spritecollide`` and ``groupcollide``) +to do this for you. + + +.. _makegames-4-1-2: + +4.1.2. Diversion 2: Vector physics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Other than the structure of the ``Ball`` class, the notable thing about this code is the vector physics, used to calculate +the ball's movement. With any game involving angular movement, you won't get very far unless you're comfortable with trigonometry, so +I'll just introduce the basics you need to know to make sense of the ``calcnewpos`` function. + +To begin with, you'll notice that the ball has an attribute ``vector``, which is made up of ``angle`` and ``z``. +The angle is measured in radians, and will give you the direction in which the ball is moving. Z is the speed at which the ball +moves. So by using this vector, we can determine the direction and speed of the ball, and therefore how much it will move on the x and +y axes: + +.. image:: tom_radians.png + +The diagram above illustrates the basic maths behind vectors. In the left hand diagram, you can see the ball's projected movement +represented by the blue line. The length of that line (z) represents its speed, and the angle is the direction in which +it will move. The angle for the ball's movement will always be taken from the x axis on the right, and it is measured clockwise from +that line, as shown in the diagram. + +From the angle and speed of the ball, we can then work out how much it has moved along the x and y axes. We need to do this because +Pygame doesn't support vectors itself, and we can only move the ball by moving its rectangle along the two axes. So we need to +:firstterm:`resolve` the angle and speed into its movement on the x axis (dx) and on the y axis (dy). This is a simple matter of +trigonometry, and can be done with the formulae shown in the diagram. + +If you've studied elementary trigonometry before, none of this should be news to you. But just in case you're forgetful, here are some +useful formulae to remember, that will help you visualise the angles (I find it easier to visualise angles in degrees than in radians!) + +.. image:: tom_formulae.png + diff --git a/docs/tut/tom_games5.rst b/docs/tut/tom_games5.rst new file mode 100644 index 0000000..bcfae12 --- /dev/null +++ b/docs/tut/tom_games5.rst @@ -0,0 +1,121 @@ +.. include:: common.txt + +***************************** + User-controllable objects +***************************** + +.. _makegames-5: + +5. User-controllable objects +============================ + +So far you can create a Pygame window, and render a ball that will fly across the screen. The next step is to make some bats which +the user can control. This is potentially far more simple than the ball, because it requires no physics (unless your user-controlled +object will move in ways more complex than up and down, e.g. a platform character like Mario, in which case you'll need more physics). +User-controllable objects are pretty easy to create, thanks to Pygame's event queue system, as you'll see. + + +.. _makegames-5-1: + +5.1. A simple bat class +----------------------- + +The principle behind the bat class is similar to that of the ball class. You need an ``__init__`` function to initialise the +ball (so you can create object instances for each bat), an ``update`` function to perform per-frame changes on the bat before +it is blitted the bat to the screen, and the functions that will define what this class will actually do. Here's some sample code:: + + class Bat(pygame.sprite.Sprite): + """Movable tennis 'bat' with which one hits the ball + Returns: bat object + Functions: reinit, update, moveup, movedown + Attributes: which, speed""" + + def __init__(self, side): + pygame.sprite.Sprite.__init__(self) + self.image, self.rect = load_png("bat.png") + screen = pygame.display.get_surface() + self.area = screen.get_rect() + self.side = side + self.speed = 10 + self.state = "still" + self.reinit() + + def reinit(self): + self.state = "still" + self.movepos = [0,0] + if self.side == "left": + self.rect.midleft = self.area.midleft + elif self.side == "right": + self.rect.midright = self.area.midright + + def update(self): + newpos = self.rect.move(self.movepos) + if self.area.contains(newpos): + self.rect = newpos + pygame.event.pump() + + def moveup(self): + self.movepos[1] = self.movepos[1] - (self.speed) + self.state = "moveup" + + def movedown(self): + self.movepos[1] = self.movepos[1] + (self.speed) + self.state = "movedown" + +As you can see, this class is very similar to the ball class in its structure. But there are differences in what each function does. +First of all, there is a reinit function, which is used when a round ends, and the bat needs to be set back in its starting place, +with any attributes set back to their necessary values. Next, the way in which the bat is moved is a little more complex than with the +ball, because here its movement is simple (up/down), but it relies on the user telling it to move, unlike the ball which just keeps +moving in every frame. To make sense of how the bat moves, it is helpful to look at a quick diagram to show the sequence of events: + +.. image:: tom_event-flowchart.png + +What happens here is that the person controlling the bat pushes down on the key that moves the bat up. For each iteration of the main +game loop (for every frame), if the key is still held down, then the ``state`` attribute of that bat object will be set to +"moving", and the ``moveup`` function will be called, causing the ball's y position to be reduced by the value of the +``speed`` attribute (in this example, 10). In other words, so long as the key is held down, the bat will move up the screen +by 10 pixels per frame. The ``state`` attribute isn't used here yet, but it's useful to know if you're dealing with spin, or +would like some useful debugging output. + +As soon as the player lets go of that key, the second set of boxes is invoked, and the ``state`` attribute of the bat object +will be set back to "still", and the ``movepos`` attribute will be set back to [0,0], meaning that when the ``update`` function is called, it won't move the bat any more. So when the player lets go of the key, the bat stops moving. Simple! + + +.. _makegames-5-1-1: + +5.1.1. Diversion 3: Pygame events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So how do we know when the player is pushing keys down, and then releasing them? With the Pygame event queue system, dummy! It's a +really easy system to use and understand, so this shouldn't take long :) You've already seen the event queue in action in the basic +Pygame program, where it was used to check if the user was quitting the application. The code for moving the bat is about as simple +as that:: + + for event in pygame.event.get(): + if event.type == QUIT: + return + elif event.type == KEYDOWN: + if event.key == K_UP: + player.moveup() + if event.key == K_DOWN: + player.movedown() + elif event.type == KEYUP: + if event.key == K_UP or event.key == K_DOWN: + player.movepos = [0,0] + player.state = "still" + +Here assume that you've already created an instance of a bat, and called the object ``player``. You can see the familiar +layout of the ``for`` structure, which iterates through each event found in the Pygame event queue, which is retrieved with +the :mod:`event.get() ` function. As the user hits keys, pushes mouse buttons and moves the joystick about, those actions are +pumped into the Pygame event queue, and left there until dealt with. So in each iteration of the main game loop, you go through +these events, checking if they're ones you want to deal with, and then dealing with them appropriately. The :func:`event.pump() ` +function that was in the ``Bat.update`` function is then called in every iteration to pump out old events, and keep the queue +current. + +First we check if the user is quitting the program, and quit it if they are. Then we check if any keys are being pushed down, and if +they are, we check if they're the designated keys for moving the bat up and down. If they are, then we call the appropriate moving +function, and set the player state appropriately (though the states moveup and movedown and changed in the ``moveup()`` and +``movedown()`` functions, which makes for neater code, and doesn't break *encapsulation*, which means that you +assign attributes to the object itself, without referring to the name of the instance of that object). Notice here we have three +states: still, moveup, and movedown. Again, these come in handy if you want to debug or calculate spin. We also check if any keys have +been "let go" (i.e. are no longer being held down), and again if they're the right keys, we stop the bat from moving. diff --git a/docs/tut/tom_games6.rst b/docs/tut/tom_games6.rst new file mode 100644 index 0000000..75f28f8 --- /dev/null +++ b/docs/tut/tom_games6.rst @@ -0,0 +1,330 @@ +.. include:: common.txt + +*************************** + Putting it all together +*************************** + +.. _makegames-6: + +6. Putting it all together +============================ + +So far you've learnt all the basics necessary to build a simple game. You should understand how to create Pygame objects, how Pygame +displays objects, how it handles events, and how you can use physics to introduce some motion into your game. Now I'll just show how +you can take all those chunks of code and put them together into a working game. What we need first is to let the ball hit the sides +of the screen, and for the bat to be able to hit the ball, otherwise there's not going to be much gameplay involved. We do this +using Pygame's :meth:`collision ` methods. + + +.. _makegames-6-1: + +6.1. Let the ball hit sides +--------------------------- + +The basic principle behind making it bounce of the sides is easy to grasp. You grab the coordinates of the four corners of the ball, +and check to see if they correspond with the x or y coordinate of the edge of the screen. So if the top right and top left corners both +have a y coordinate of zero, you know that the ball is currently on the top edge of the screen. We do all this in the ``update`` function, +after we've worked out the new position of the ball. + +:: + + if not self.area.contains(newpos): + tl = not self.area.collidepoint(newpos.topleft) + tr = not self.area.collidepoint(newpos.topright) + bl = not self.area.collidepoint(newpos.bottomleft) + br = not self.area.collidepoint(newpos.bottomright) + if tr and tl or (br and bl): + angle = -angle + if tl and bl: + self.offcourt(player=2) + if tr and br: + self.offcourt(player=1) + + self.vector = (angle,z) + +Here we check to see if the ``area`` +contains the new position of the ball (it always should, so we needn't have an ``else`` clause, +though in other circumstances you might want to consider it). We then check if the coordinates for the four corners +are *colliding* with the area's edges, and create objects for each result. If they are, the objects will have a value of 1, +or ``True``. If they don't, then the value will be ``None``, or ``False``. We then see if it has hit the top or bottom, and if it +has we change the ball's direction. Handily, using radians we can do this by simply reversing its positive/negative value. +We also check to see if the ball has gone off the sides, and if it has we call the ``offcourt`` function. +This, in my game, resets the ball, adds 1 point to the score of the player specified when calling the function, and displays the new score. + +Finally, we recompile the vector based on the new angle. And that is it. The ball will now merrily bounce off the walls and go +offcourt with good grace. + + +.. _makegames-6-2: + +6.2. Let the ball hit bats +-------------------------- + +Making the ball hit the bats is very similar to making it hit the sides of the screen. We still use the collide method, but this time +we check to see if the rectangles for the ball and either bat collide. In this code I've also put in some extra code to avoid various +glitches. You'll find that you'll have to put all sorts of extra code in to avoid glitches and bugs, so it's good to get used to seeing +it. + +:: + + else: + # Deflate the rectangles so you can't catch a ball behind the bat + player1.rect.inflate(-3, -3) + player2.rect.inflate(-3, -3) + + # Do ball and bat collide? + # Note I put in an odd rule that sets self.hit to 1 when they collide, and unsets it in the next + # iteration. this is to stop odd ball behaviour where it finds a collision *inside* the + # bat, the ball reverses, and is still inside the bat, so bounces around inside. + # This way, the ball can always escape and bounce away cleanly + if self.rect.colliderect(player1.rect) == 1 and not self.hit: + angle = math.pi - angle + self.hit = not self.hit + elif self.rect.colliderect(player2.rect) == 1 and not self.hit: + angle = math.pi - angle + self.hit = not self.hit + elif self.hit: + self.hit = not self.hit + self.vector = (angle,z) + +We start this section with an ``else`` statement, because this carries on from the previous chunk of code to check if the ball +hits the sides. It makes sense that if it doesn't hit the sides, it might hit a bat, so we carry on the conditional statement. The +first glitch to fix is to shrink the players' rectangles by 3 pixels in both dimensions, to stop the bat catching a ball that goes +behind them (if you imagine you just move the bat so that as the ball travels behind it, the rectangles overlap, and so normally the +ball would then have been "hit" - this prevents that). + +Next we check if the rectangles collide, with one more glitch fix. Notice that I've commented on these odd bits of code - it's always +good to explain bits of code that are abnormal, both for others who look at your code, and so you understand it when you come back to +it. The without the fix, the ball might hit a corner of the bat, change direction, and one frame later still find itself inside the +bat. Then it would again think it has been hit, and change its direction. This can happen several times, making the ball's motion +completely unrealistic. So we have a variable, ``self.hit``, which we set to ``True`` when it has been hit, and ``False`` one frame +later. When we check if the rectangles have collided, we also check if ``self.hit`` is ``True``/``False``, to stop internal bouncing. + +The important code here is pretty easy to understand. All rectangles have a :meth:`colliderect ` +function, into which you feed the rectangle of another object, which returns ``True`` if the rectangles do overlap, and ``False`` if not. +If they do, we can change the direction by subtracting the current angle from ``pi`` (again, a handy trick you can do with radians, +which will adjust the angle by 90 degrees and send it off in the right direction; you might find at this point that a thorough +understanding of radians is in order!). Just to finish the glitch checking, we switch ``self.hit`` back to ``False`` if it's the frame +after they were hit. + +We also then recompile the vector. You would of course want to remove the same line in the previous chunk of code, so that you only do +this once after the ``if-else`` conditional statement. And that's it! The combined code will now allow the ball to hit sides and bats. + + +.. _makegames-6-3: + +6.3. The Finished product +------------------------- + +The final product, with all the bits of code thrown together, as well as some other bits ofcode to glue it all together, will look +like this:: + + # + # Tom's Pong + # A simple pong game with realistic physics and AI + # http://tomchance.org.uk/projects/pong + # + # Released under the GNU General Public License + + VERSION = "0.4" + + try: + import sys + import random + import math + import os + import getopt + import pygame + from socket import * + from pygame.locals import * + except ImportError, err: + print(f"couldn't load module. {err}") + sys.exit(2) + + def load_png(name): + """ Load image and return image object""" + fullname = os.path.join("data", name) + try: + image = pygame.image.load(fullname) + if image.get_alpha is None: + image = image.convert() + else: + image = image.convert_alpha() + except FileNotFoundError: + print(f"Cannot load image: {fullname}") + raise SystemExit + return image, image.get_rect() + + class Ball(pygame.sprite.Sprite): + """A ball that will move across the screen + Returns: ball object + Functions: update, calcnewpos + Attributes: area, vector""" + + def __init__(self, (xy), vector): + pygame.sprite.Sprite.__init__(self) + self.image, self.rect = load_png("ball.png") + screen = pygame.display.get_surface() + self.area = screen.get_rect() + self.vector = vector + self.hit = 0 + + def update(self): + newpos = self.calcnewpos(self.rect,self.vector) + self.rect = newpos + (angle,z) = self.vector + + if not self.area.contains(newpos): + tl = not self.area.collidepoint(newpos.topleft) + tr = not self.area.collidepoint(newpos.topright) + bl = not self.area.collidepoint(newpos.bottomleft) + br = not self.area.collidepoint(newpos.bottomright) + if tr and tl or (br and bl): + angle = -angle + if tl and bl: + #self.offcourt() + angle = math.pi - angle + if tr and br: + angle = math.pi - angle + #self.offcourt() + else: + # Deflate the rectangles so you can't catch a ball behind the bat + player1.rect.inflate(-3, -3) + player2.rect.inflate(-3, -3) + + # Do ball and bat collide? + # Note I put in an odd rule that sets self.hit to 1 when they collide, and unsets it in the next + # iteration. this is to stop odd ball behaviour where it finds a collision *inside* the + # bat, the ball reverses, and is still inside the bat, so bounces around inside. + # This way, the ball can always escape and bounce away cleanly + if self.rect.colliderect(player1.rect) == 1 and not self.hit: + angle = math.pi - angle + self.hit = not self.hit + elif self.rect.colliderect(player2.rect) == 1 and not self.hit: + angle = math.pi - angle + self.hit = not self.hit + elif self.hit: + self.hit = not self.hit + self.vector = (angle,z) + + def calcnewpos(self,rect,vector): + (angle,z) = vector + (dx,dy) = (z*math.cos(angle),z*math.sin(angle)) + return rect.move(dx,dy) + + class Bat(pygame.sprite.Sprite): + """Movable tennis 'bat' with which one hits the ball + Returns: bat object + Functions: reinit, update, moveup, movedown + Attributes: which, speed""" + + def __init__(self, side): + pygame.sprite.Sprite.__init__(self) + self.image, self.rect = load_png("bat.png") + screen = pygame.display.get_surface() + self.area = screen.get_rect() + self.side = side + self.speed = 10 + self.state = "still" + self.reinit() + + def reinit(self): + self.state = "still" + self.movepos = [0,0] + if self.side == "left": + self.rect.midleft = self.area.midleft + elif self.side == "right": + self.rect.midright = self.area.midright + + def update(self): + newpos = self.rect.move(self.movepos) + if self.area.contains(newpos): + self.rect = newpos + pygame.event.pump() + + def moveup(self): + self.movepos[1] = self.movepos[1] - (self.speed) + self.state = "moveup" + + def movedown(self): + self.movepos[1] = self.movepos[1] + (self.speed) + self.state = "movedown" + + + def main(): + # Initialise screen + pygame.init() + screen = pygame.display.set_mode((640, 480)) + pygame.display.set_caption("Basic Pong") + + # Fill background + background = pygame.Surface(screen.get_size()) + background = background.convert() + background.fill((0, 0, 0)) + + # Initialise players + global player1 + global player2 + player1 = Bat("left") + player2 = Bat("right") + + # Initialise ball + speed = 13 + rand = ((0.1 * (random.randint(5,8)))) + ball = Ball((0,0),(0.47,speed)) + + # Initialise sprites + playersprites = pygame.sprite.RenderPlain((player1, player2)) + ballsprite = pygame.sprite.RenderPlain(ball) + + # Blit everything to the screen + screen.blit(background, (0, 0)) + pygame.display.flip() + + # Initialise clock + clock = pygame.time.Clock() + + # Event loop + while True: + # Make sure game doesn't run at more than 60 frames per second + clock.tick(60) + + for event in pygame.event.get(): + if event.type == QUIT: + return + elif event.type == KEYDOWN: + if event.key == K_a: + player1.moveup() + if event.key == K_z: + player1.movedown() + if event.key == K_UP: + player2.moveup() + if event.key == K_DOWN: + player2.movedown() + elif event.type == KEYUP: + if event.key == K_a or event.key == K_z: + player1.movepos = [0,0] + player1.state = "still" + if event.key == K_UP or event.key == K_DOWN: + player2.movepos = [0,0] + player2.state = "still" + + screen.blit(background, ball.rect, ball.rect) + screen.blit(background, player1.rect, player1.rect) + screen.blit(background, player2.rect, player2.rect) + ballsprite.update() + playersprites.update() + ballsprite.draw(screen) + playersprites.draw(screen) + pygame.display.flip() + + + if __name__ == "__main__": + main() + + +As well as showing you the final product, I'll point you back to TomPong, upon which all of this is based. Download it, have a look +at the source code, and you'll see a full implementation of pong using all of the code you've seen in this tutorial, as well as lots of +other code I've added in various versions, such as some extra physics for spinning, and various other bug and glitch fixes. + +Oh, find TomPong at http://tomchance.org.uk/projects/pong. diff --git a/docs/tut/tom_radians.png b/docs/tut/tom_radians.png new file mode 100644 index 0000000000000000000000000000000000000000..4569df1cb4ab3aef4c064b3a71f0fdb8af0c9bff GIT binary patch literal 17409 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