├── .gitignore
├── MANIFEST.in
├── README
├── README.pygame
├── VERSION_NUMBERING
├── WHATSNEW
├── WHATSNEW.pygame
├── doc-src
├── Makefile
├── _static
│ ├── LICENSES
│ ├── favicon.ico
│ └── sge_logo_alpha_black.png
├── collision.rst
├── conf.py
├── dsp.rst
├── gfx.rst
├── hello_world.rst
├── index.rst
├── input.rst
├── joystick.rst
├── keyboard.rst
├── make.bat
├── mouse.rst
├── pong.rst
├── pong_better.rst
├── s.rst
├── sge.rst
└── snd.rst
├── examples
├── cc0-1.0.txt
├── circle_popper.py
├── data
│ ├── LICENSES
│ ├── WhereWasI.ogg
│ ├── bounce.wav
│ ├── bounce_wall.wav
│ ├── circle.png
│ ├── circle_pop-0.png
│ ├── circle_pop-1.png
│ ├── circle_pop-10.png
│ ├── circle_pop-11.png
│ ├── circle_pop-12.png
│ ├── circle_pop-2.png
│ ├── circle_pop-3.png
│ ├── circle_pop-4.png
│ ├── circle_pop-5.png
│ ├── circle_pop-6.png
│ ├── circle_pop-7.png
│ ├── circle_pop-8.png
│ ├── circle_pop-9.png
│ ├── fence.png
│ ├── pop.ogg
│ ├── rotator.png
│ └── score.wav
├── jstest.py
├── large_room.py
├── pong.py
├── rotation.py
├── splitscreen.py
└── transitions.py
├── pyproject.toml
├── setup.py
└── sge
├── COPYING
├── COPYING.LESSER
├── __init__.py
├── collision.py
├── dsp.py
├── gfx.py
├── input.py
├── joystick.py
├── keyboard.py
├── mouse.py
├── r.py
├── s.py
└── snd.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[co]
2 |
3 | # Packages
4 | *.egg
5 | *.egg-info
6 | dist
7 | doc
8 | build
9 | eggs
10 | parts
11 | bin
12 | var
13 | sdist
14 | develop-eggs
15 | .installed.cfg
16 | _build
17 |
18 | # Installer logs
19 | pip-log.txt
20 |
21 | # Unit test / coverage reports
22 | .coverage
23 | .tox
24 |
25 | #Translations
26 | *.mo
27 |
28 | #Mr Developer
29 | .mr.developer.cfg
30 |
31 | MANIFEST
32 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.* WHATSNEW WHATSNEW.* VERSION_NUMBERING MANIFEST.in pyproject.toml
2 | recursive-include doc *
3 | recursive-include doc-src *
4 | recursive-include examples *
5 | global-include COPYING COPYING.* LICENSE LICENSES
6 | global-exclude *~ *.pyc *.pyo
7 | prune build
8 | prune dist
9 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This file has been dedicated to the public domain, to the extent
2 | possible under applicable law, via CC0. See
3 | http://creativecommons.org/publicdomain/zero/1.0/ for more
4 | information. This file is offered as-is, without any warranty.
5 |
6 | ========================================================================
7 |
8 | LICENSE
9 |
10 | The Pygame SGE is free software: you can redistribute it and/or modify
11 | it under the terms of the GNU Lesser General Public License as published by
12 | the Free Software Foundation, either version 3 of the License, or
13 | (at your option) any later version.
14 |
15 | The Pygame SGE is distributed in the hope that it will be useful,
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | GNU Lesser General Public License for more details.
19 |
20 | You should have received a copy of the GNU Lesser General Public License
21 | along with the Pygame SGE. If not, see .
22 |
23 |
24 | INSTALLATION
25 |
26 | First, install the dependencies:
27 |
28 | - Python 3.6 or later
29 | - Pygame 2.0 or later
30 | - uniseg
31 |
32 | Once you have all the dependencies, install the SGE with the included
33 | setup.py script, e.g. with "python setup.py install".
34 |
35 | Alternatively, you can just place the "sge" folder into the same
36 | directory as the Python program that uses it. This can be a good idea
37 | for the distribution of a game, since it reduces the number of
38 | dependencies the user needs to install.
39 |
40 |
41 | USAGE
42 |
43 | See the "doc" folder for detailed documentation on how to use the SGE.
44 |
45 |
46 | PYGAME SGE IMPLEMENTATION DETAILS
47 |
48 | See README.pygame for information specific to the Pygame SGE.
49 |
50 |
--------------------------------------------------------------------------------
/README.pygame:
--------------------------------------------------------------------------------
1 | This file has been dedicated to the public domain, to the extent
2 | possible under applicable law, via CC0. See
3 | http://creativecommons.org/publicdomain/zero/1.0/ for more
4 | information. This file is offered as-is, without any warranty.
5 |
6 | ========================================================================
7 |
8 | This file details specifics of the Pygame SGE implementation which
9 | may be useful to know.
10 |
11 |
12 | FORMATS SUPPORT
13 |
14 | sge.gfx.Sprite supports the following image formats if Pygame is built
15 | with full image support:
16 |
17 | - PNG
18 | - JPEG
19 | - Non-animated GIF
20 | - BMP
21 | - PCX
22 | - Uncompressed Truevision TGA
23 | - TIFF
24 | - ILBM
25 | - Netpbm
26 | - X Pixmap
27 |
28 | If Pygame is built without full image support, sge.gfx.Sprite will only
29 | be able to load uncompressed BMP images.
30 |
31 | sge.snd.Sound supports the following audio formats:
32 |
33 | - Uncompressed WAV
34 | - Ogg Vorbis
35 |
36 | sge.snd.Music supports the following audio formats:
37 |
38 | - Ogg Vorbis
39 | - MOD
40 | - XM
41 | - MIDI
42 |
43 | MP3 is also supported on some systems, but not all. On some systems,
44 | attempting to load an unsupported format can crash the game. Since MP3
45 | support is not available on all systems, it is best to avoid using it;
46 | consider using Ogg Vorbis instead.
47 |
48 | For starting position in MOD files, the pattern order number is used
49 | instead of the number of milliseconds.
50 |
51 | The pygame.mixer module, which is used for all audio playback, is
52 | optional and depends on SDL_mixer; if pygame.mixer is unavailable,
53 | sounds and music will not play.
54 |
55 |
--------------------------------------------------------------------------------
/VERSION_NUMBERING:
--------------------------------------------------------------------------------
1 | This file has been dedicated to the public domain, to the extent
2 | possible under applicable law, via CC0. See
3 | http://creativecommons.org/publicdomain/zero/1.0/ for more
4 | information. This file is offered as-is, without any warranty.
5 |
6 | ========================================================================
7 |
8 | This is an explanation of the SGE's version numbering, in particular how
9 | it indicates compatibility between various SGE releases.
10 |
11 | The SGE specification has only two components to its version number: the
12 | major version, and the minor version.
13 |
14 | Two versions of the SGE specification with different major version
15 | numbers can be expected to be incompatible. For example, there is no
16 | guarantee that a program designed for version 1.0 of the SGE will work
17 | with version 2.0 of the SGE.
18 |
19 | A version of the SGE specification with the same major version number,
20 | but a higher minor version number, than another version of the SGE
21 | specification can be assumed to be backward-compatible. This number is
22 | used to indicate things like unintrusive feature additions. For
23 | example, it can be expected that a program designed for version 1.0 of
24 | the SGE will work with version 1.1 of the SGE.
25 |
26 | As a special exception, two versions of the SGE with the major version
27 | number 0, but a different minor version number, can be expected to be
28 | incompatible (i.e. the minor version number is treated as the major
29 | version number). The major version number 0 is to be used until the
30 | specification has been properly tested (by developing a full,
31 | non-trivial game with it), so that it can be sure that version 1.0 of
32 | the specification is reasonably complete.
33 |
34 | SGE implementations, like the Pygame SGE, have either two or three
35 | components to their version numbers. The first two components should
36 | match the specification version they are implementing; for example,
37 | version 0.12 of the Pygame SGE implements version 0.12 of the SGE
38 | specification.
39 |
40 | The optional third component should be used to indicate any
41 | implementation-specific changes, such as bugfixes.
42 |
--------------------------------------------------------------------------------
/doc-src/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SOURCEDIR = .
8 | BUILDDIR = ../doc
9 |
10 | # Put it first so that "make" without argument is like "make help".
11 | help:
12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13 |
14 | .PHONY: help Makefile
15 |
16 | # Catch-all target: route all unknown targets to Sphinx using the new
17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
18 | %: Makefile
19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
--------------------------------------------------------------------------------
/doc-src/_static/LICENSES:
--------------------------------------------------------------------------------
1 | This file lists the licenses, authors, and sources for all the
2 | non-functional data files found in this directory.
3 |
4 | ========================================================================
5 |
6 | sge_logo_alpha_black.png
7 |
8 | Authors:
9 | Francisco Cifuentes
10 | Modified by Layla Marchant
11 | License: CC BY 3.0
12 |
13 | ------------------------------------------------------------------------
14 |
15 | favicon.ico
16 |
17 | Authors:
18 | Layla Marchant
19 | Based on SGE logo by Francisco Cifuentes
20 | License: CC BY 3.0
21 |
--------------------------------------------------------------------------------
/doc-src/_static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/doc-src/_static/favicon.ico
--------------------------------------------------------------------------------
/doc-src/_static/sge_logo_alpha_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/doc-src/_static/sge_logo_alpha_black.png
--------------------------------------------------------------------------------
/doc-src/collision.rst:
--------------------------------------------------------------------------------
1 | *************
2 | sge.collision
3 | *************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.collision
13 |
14 | sge.collision Functions
15 | =======================
16 |
17 | .. autofunction:: sge.collision.rectangles_collide
18 |
19 | .. autofunction:: sge.collision.masks_collide
20 |
21 | .. autofunction:: sge.collision.rectangle
22 |
23 | .. autofunction:: sge.collision.ellipse
24 |
25 | .. autofunction:: sge.collision.circle
26 |
27 | .. autofunction:: sge.collision.line
28 |
--------------------------------------------------------------------------------
/doc-src/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Configuration file for the Sphinx documentation builder.
4 | #
5 | # This file does only contain a selection of the most common options. For a
6 | # full list see the documentation:
7 | # http://www.sphinx-doc.org/en/master/config
8 |
9 | # -- Path setup --------------------------------------------------------------
10 |
11 | # If extensions (or modules to document with autodoc) are in another directory,
12 | # add these directories to sys.path here. If the directory is relative to the
13 | # documentation root, use os.path.abspath to make it absolute, like shown here.
14 | #
15 | # import os
16 | # import sys
17 | # sys.path.insert(0, os.path.abspath('.'))
18 |
19 |
20 | # -- Project information -----------------------------------------------------
21 |
22 | project = 'Seclusion Game Engine'
23 | copyright = ''
24 | author = 'The Diligent Circle'
25 |
26 | # The short X.Y version
27 | version = '2.0'
28 | # The full version, including alpha/beta/rc tags
29 | release = '2.0.3'
30 |
31 |
32 | # -- General configuration ---------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | #
36 | # needs_sphinx = '1.0'
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be
39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 | # ones.
41 | extensions = [
42 | 'sphinx.ext.autodoc',
43 | ]
44 |
45 | # Add any paths that contain templates here, relative to this directory.
46 | templates_path = ['_templates']
47 |
48 | # The suffix(es) of source filenames.
49 | # You can specify multiple suffix as a list of string:
50 | #
51 | # source_suffix = ['.rst', '.md']
52 | source_suffix = '.rst'
53 |
54 | # The master toctree document.
55 | master_doc = 'index'
56 |
57 | # The language for content autogenerated by Sphinx. Refer to documentation
58 | # for a list of supported languages.
59 | #
60 | # This is also used if you do content translation via gettext catalogs.
61 | # Usually you set "language" from the command line for these cases.
62 | language = None
63 |
64 | # List of patterns, relative to source directory, that match files and
65 | # directories to ignore when looking for source files.
66 | # This pattern also affects html_static_path and html_extra_path.
67 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
68 |
69 | # The name of the Pygments (syntax highlighting) style to use.
70 | pygments_style = None
71 |
72 |
73 | # -- Options for HTML output -------------------------------------------------
74 |
75 | # The theme to use for HTML and HTML Help pages. See the documentation for
76 | # a list of builtin themes.
77 | #
78 | html_theme = 'alabaster'
79 |
80 | # Theme options are theme-specific and customize the look and feel of a theme
81 | # further. For a list of options available for each theme, see the
82 | # documentation.
83 | #
84 | # html_theme_options = {}
85 |
86 | html_logo = "_static/sge_logo_alpha_black.png"
87 | html_favicon = "_static/favicon.ico"
88 |
89 | # Add any paths that contain custom static files (such as style sheets) here,
90 | # relative to this directory. They are copied after the builtin static files,
91 | # so a file named "default.css" will overwrite the builtin "default.css".
92 | html_static_path = ['_static']
93 |
94 | # Custom sidebar templates, must be a dictionary that maps document names
95 | # to template names.
96 | #
97 | # The default sidebars (for documents that don't match any pattern) are
98 | # defined by theme itself. Builtin themes are using these templates by
99 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
100 | # 'searchbox.html']``.
101 | #
102 | # html_sidebars = {}
103 |
104 |
105 | # -- Options for HTMLHelp output ---------------------------------------------
106 |
107 | # Output file base name for HTML help builder.
108 | htmlhelp_basename = 'SGEdoc'
109 |
110 |
111 | # -- Options for LaTeX output ------------------------------------------------
112 |
113 | latex_elements = {
114 | # The paper size ('letterpaper' or 'a4paper').
115 | #
116 | # 'papersize': 'letterpaper',
117 |
118 | # The font size ('10pt', '11pt' or '12pt').
119 | #
120 | # 'pointsize': '10pt',
121 |
122 | # Additional stuff for the LaTeX preamble.
123 | #
124 | # 'preamble': '',
125 |
126 | # Latex figure (float) alignment
127 | #
128 | # 'figure_align': 'htbp',
129 | }
130 |
131 | # Grouping the document tree into LaTeX files. List of tuples
132 | # (source start file, target name, title,
133 | # author, documentclass [howto, manual, or own class]).
134 | latex_documents = [
135 | (master_doc, 'SGE.tex', 'Seclusion Game Engine Documentation',
136 | 'The Diligent Circle', 'manual'),
137 | ]
138 |
139 |
140 | # -- Options for manual page output ------------------------------------------
141 |
142 | # One entry per manual page. List of tuples
143 | # (source start file, name, description, authors, manual section).
144 | man_pages = [
145 | (master_doc, 'SGE', 'Seclusion Game Engine Documentation',
146 | [author], 1)
147 | ]
148 |
149 |
150 | # -- Options for Texinfo output ----------------------------------------------
151 |
152 | # Grouping the document tree into Texinfo files. List of tuples
153 | # (source start file, target name, title, author,
154 | # dir menu entry, description, category)
155 | texinfo_documents = [
156 | (master_doc, 'SGE', 'Seclusion Game Engine Documentation',
157 | author, 'SGE', '',
158 | 'Miscellaneous'),
159 | ]
160 |
161 |
162 | # -- Options for Epub output -------------------------------------------------
163 |
164 | # Bibliographic Dublin Core info.
165 | epub_title = project
166 |
167 | # The unique identifier of the text. This can be a ISBN number
168 | # or the project homepage.
169 | #
170 | # epub_identifier = ''
171 |
172 | # A unique identification for the text.
173 | #
174 | # epub_uid = ''
175 |
176 | # A list of files that should not be packed into the epub file.
177 | epub_exclude_files = ['search.html']
178 |
179 |
180 | # -- Extension configuration -------------------------------------------------
181 |
--------------------------------------------------------------------------------
/doc-src/dsp.rst:
--------------------------------------------------------------------------------
1 | *******
2 | sge.dsp
3 | *******
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.dsp
13 |
14 | sge.dsp Classes
15 | ===============
16 |
17 | sge.dsp.Game
18 | ------------
19 |
20 | .. autoclass:: sge.dsp.Game
21 |
22 | .. automethod:: sge.dsp.Game.__init__
23 |
24 | sge.dsp.Game Methods
25 | ~~~~~~~~~~~~~~~~~~~~
26 |
27 | .. automethod:: sge.dsp.Game.start
28 |
29 | .. automethod:: sge.dsp.Game.end
30 |
31 | .. automethod:: sge.dsp.Game.pause
32 |
33 | .. automethod:: sge.dsp.Game.unpause
34 |
35 | .. automethod:: sge.dsp.Game.pump_input
36 |
37 | .. automethod:: sge.dsp.Game.regulate_speed
38 |
39 | .. automethod:: sge.dsp.Game.refresh
40 |
41 | .. automethod:: sge.dsp.Game.project_dot
42 |
43 | .. automethod:: sge.dsp.Game.project_line
44 |
45 | .. automethod:: sge.dsp.Game.project_rectangle
46 |
47 | .. automethod:: sge.dsp.Game.project_ellipse
48 |
49 | .. automethod:: sge.dsp.Game.project_circle
50 |
51 | .. automethod:: sge.dsp.Game.project_polyline
52 |
53 | .. automethod:: sge.dsp.Game.project_polygon
54 |
55 | .. automethod:: sge.dsp.Game.project_sprite
56 |
57 | .. automethod:: sge.dsp.Game.project_text
58 |
59 | sge.dsp.Game Event Methods
60 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
61 |
62 | .. automethod:: sge.dsp.Game.event_step
63 |
64 | .. automethod:: sge.dsp.Game.event_alarm
65 |
66 | .. automethod:: sge.dsp.Game.event_key_press
67 |
68 | .. automethod:: sge.dsp.Game.event_key_release
69 |
70 | .. automethod:: sge.dsp.Game.event_mouse_move
71 |
72 | .. automethod:: sge.dsp.Game.event_mouse_button_press
73 |
74 | .. automethod:: sge.dsp.Game.event_mouse_button_release
75 |
76 | .. automethod:: sge.dsp.Game.event_mouse_wheel_move
77 |
78 | .. automethod:: sge.dsp.Game.event_joystick
79 |
80 | .. automethod:: sge.dsp.Game.event_joystick_axis_move
81 |
82 | .. automethod:: sge.dsp.Game.event_joystick_hat_move
83 |
84 | .. automethod:: sge.dsp.Game.event_joystick_trackball_move
85 |
86 | .. automethod:: sge.dsp.Game.event_joystick_button_press
87 |
88 | .. automethod:: sge.dsp.Game.event_joystick_button_release
89 |
90 | .. automethod:: sge.dsp.Game.event_gain_keyboard_focus
91 |
92 | .. automethod:: sge.dsp.Game.event_lose_keyboard_focus
93 |
94 | .. automethod:: sge.dsp.Game.event_gain_mouse_focus
95 |
96 | .. automethod:: sge.dsp.Game.event_lose_mouse_focus
97 |
98 | .. automethod:: sge.dsp.Game.event_window_resize
99 |
100 | .. automethod:: sge.dsp.Game.event_close
101 |
102 | .. automethod:: sge.dsp.Game.event_mouse_collision
103 |
104 | .. automethod:: sge.dsp.Game.event_paused_step
105 |
106 | .. automethod:: sge.dsp.Game.event_paused_key_press
107 |
108 | .. automethod:: sge.dsp.Game.event_paused_key_release
109 |
110 | .. automethod:: sge.dsp.Game.event_paused_mouse_move
111 |
112 | .. automethod:: sge.dsp.Game.event_paused_mouse_button_press
113 |
114 | .. automethod:: sge.dsp.Game.event_paused_mouse_button_release
115 |
116 | .. automethod:: sge.dsp.Game.event_paused_mouse_wheel_move
117 |
118 | .. automethod:: sge.dsp.Game.event_paused_joystick
119 |
120 | .. automethod:: sge.dsp.Game.event_paused_joystick_axis_move
121 |
122 | .. automethod:: sge.dsp.Game.event_paused_joystick_hat_move
123 |
124 | .. automethod:: sge.dsp.Game.event_paused_joystick_trackball_move
125 |
126 | .. automethod:: sge.dsp.Game.event_paused_joystick_button_press
127 |
128 | .. automethod:: sge.dsp.Game.event_paused_joystick_button_release
129 |
130 | .. automethod:: sge.dsp.Game.event_paused_gain_keyboard_focus
131 |
132 | .. automethod:: sge.dsp.Game.event_paused_lose_keyboard_focus
133 |
134 | .. automethod:: sge.dsp.Game.event_paused_gain_mouse_focus
135 |
136 | .. automethod:: sge.dsp.Game.event_paused_lose_mouse_focus
137 |
138 | .. automethod:: sge.dsp.Game.event_paused_window_resize
139 |
140 | .. automethod:: sge.dsp.Game.event_paused_close
141 |
142 | sge.dsp.Room
143 | ------------
144 |
145 | .. autoclass:: sge.dsp.Room
146 |
147 | .. automethod:: sge.dsp.Room.__init__
148 |
149 | sge.dsp.Room Methods
150 | ~~~~~~~~~~~~~~~~~~~~
151 |
152 | .. automethod:: sge.dsp.Room.add
153 |
154 | .. automethod:: sge.dsp.Room.remove
155 |
156 | .. automethod:: sge.dsp.Room.start
157 |
158 | .. automethod:: sge.dsp.Room.get_objects_at
159 |
160 | .. automethod:: sge.dsp.Room.project_dot
161 |
162 | .. automethod:: sge.dsp.Room.project_line
163 |
164 | .. automethod:: sge.dsp.Room.project_rectangle
165 |
166 | .. automethod:: sge.dsp.Room.project_ellipse
167 |
168 | .. automethod:: sge.dsp.Room.project_circle
169 |
170 | .. automethod:: sge.dsp.Room.project_polyline
171 |
172 | .. automethod:: sge.dsp.Room.project_polygon
173 |
174 | .. automethod:: sge.dsp.Room.project_sprite
175 |
176 | .. automethod:: sge.dsp.Room.project_text
177 |
178 | sge.dsp.Room Event Methods
179 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
180 |
181 | .. automethod:: sge.dsp.Room.event_room_start
182 |
183 | .. automethod:: sge.dsp.Room.event_room_resume
184 |
185 | .. automethod:: sge.dsp.Room.event_room_end
186 |
187 | .. automethod:: sge.dsp.Room.event_step
188 |
189 | .. automethod:: sge.dsp.Room.event_alarm
190 |
191 | .. automethod:: sge.dsp.Room.event_key_press
192 |
193 | .. automethod:: sge.dsp.Room.event_key_release
194 |
195 | .. automethod:: sge.dsp.Room.event_mouse_move
196 |
197 | .. automethod:: sge.dsp.Room.event_mouse_button_press
198 |
199 | .. automethod:: sge.dsp.Room.event_mouse_button_release
200 |
201 | .. automethod:: sge.dsp.Room.event_mouse_wheel_move
202 |
203 | .. automethod:: sge.dsp.Room.event_joystick
204 |
205 | .. automethod:: sge.dsp.Room.event_joystick_axis_move
206 |
207 | .. automethod:: sge.dsp.Room.event_joystick_hat_move
208 |
209 | .. automethod:: sge.dsp.Room.event_joystick_trackball_move
210 |
211 | .. automethod:: sge.dsp.Room.event_joystick_button_press
212 |
213 | .. automethod:: sge.dsp.Room.event_joystick_button_release
214 |
215 | .. automethod:: sge.dsp.Room.event_gain_keyboard_focus
216 |
217 | .. automethod:: sge.dsp.Room.event_lose_keyboard_focus
218 |
219 | .. automethod:: sge.dsp.Room.event_gain_mouse_focus
220 |
221 | .. automethod:: sge.dsp.Room.event_lose_mouse_focus
222 |
223 | .. automethod:: sge.dsp.Room.event_close
224 |
225 | .. automethod:: sge.dsp.Room.event_paused_step
226 |
227 | .. automethod:: sge.dsp.Room.event_paused_key_press
228 |
229 | .. automethod:: sge.dsp.Room.event_paused_key_release
230 |
231 | .. automethod:: sge.dsp.Room.event_paused_mouse_move
232 |
233 | .. automethod:: sge.dsp.Room.event_paused_mouse_button_press
234 |
235 | .. automethod:: sge.dsp.Room.event_paused_mouse_button_release
236 |
237 | .. automethod:: sge.dsp.Room.event_paused_mouse_wheel_move
238 |
239 | .. automethod:: sge.dsp.Room.event_paused_joystick
240 |
241 | .. automethod:: sge.dsp.Room.event_paused_joystick_axis_move
242 |
243 | .. automethod:: sge.dsp.Room.event_paused_joystick_hat_move
244 |
245 | .. automethod:: sge.dsp.Room.event_paused_joystick_trackball_move
246 |
247 | .. automethod:: sge.dsp.Room.event_paused_joystick_button_press
248 |
249 | .. automethod:: sge.dsp.Room.event_paused_joystick_button_release
250 |
251 | .. automethod:: sge.dsp.Room.event_paused_gain_keyboard_focus
252 |
253 | .. automethod:: sge.dsp.Room.event_paused_lose_keyboard_focus
254 |
255 | .. automethod:: sge.dsp.Room.event_paused_gain_mouse_focus
256 |
257 | .. automethod:: sge.dsp.Room.event_paused_lose_mouse_focus
258 |
259 | .. automethod:: sge.dsp.Room.event_paused_close
260 |
261 | sge.dsp.View
262 | ------------
263 |
264 | .. autoclass:: sge.dsp.View
265 |
266 | .. automethod:: sge.dsp.View.__init__
267 |
268 | sge.dsp.Object
269 | --------------
270 |
271 | .. autoclass:: sge.dsp.Object
272 |
273 | .. automethod:: sge.dsp.Object.__init__
274 |
275 | sge.dsp.Object Methods
276 | ~~~~~~~~~~~~~~~~~~~~~~
277 |
278 | .. automethod:: sge.dsp.Object.move_x
279 |
280 | .. automethod:: sge.dsp.Object.move_y
281 |
282 | .. automethod:: sge.dsp.Object.collision
283 |
284 | .. automethod:: sge.dsp.Object.destroy
285 |
286 | .. automethod:: sge.dsp.Object.create
287 |
288 | sge.dsp.Object Event Methods
289 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
290 |
291 | .. automethod:: sge.dsp.Object.event_create
292 |
293 | .. automethod:: sge.dsp.Object.event_destroy
294 |
295 | .. automethod:: sge.dsp.Object.event_step
296 |
297 | .. automethod:: sge.dsp.Object.event_alarm
298 |
299 | .. automethod:: sge.dsp.Object.event_animation_end
300 |
301 | .. automethod:: sge.dsp.Object.event_key_press
302 |
303 | .. automethod:: sge.dsp.Object.event_key_release
304 |
305 | .. automethod:: sge.dsp.Object.event_mouse_move
306 |
307 | .. automethod:: sge.dsp.Object.event_mouse_button_press
308 |
309 | .. automethod:: sge.dsp.Object.event_mouse_button_release
310 |
311 | .. automethod:: sge.dsp.Object.event_mouse_wheel_move
312 |
313 | .. automethod:: sge.dsp.Object.event_joystick
314 |
315 | .. automethod:: sge.dsp.Object.event_joystick_axis_move
316 |
317 | .. automethod:: sge.dsp.Object.event_joystick_hat_move
318 |
319 | .. automethod:: sge.dsp.Object.event_joystick_trackball_move
320 |
321 | .. automethod:: sge.dsp.Object.event_joystick_button_press
322 |
323 | .. automethod:: sge.dsp.Object.event_joystick_button_release
324 |
325 | .. automethod:: sge.dsp.Object.event_update_position
326 |
327 | .. automethod:: sge.dsp.Object.event_collision
328 |
329 | .. automethod:: sge.dsp.Object.event_paused_step
330 |
331 | .. automethod:: sge.dsp.Object.event_paused_key_press
332 |
333 | .. automethod:: sge.dsp.Object.event_paused_key_release
334 |
335 | .. automethod:: sge.dsp.Object.event_paused_mouse_move
336 |
337 | .. automethod:: sge.dsp.Object.event_paused_mouse_button_press
338 |
339 | .. automethod:: sge.dsp.Object.event_paused_mouse_button_release
340 |
341 | .. automethod:: sge.dsp.Object.event_paused_mouse_wheel_move
342 |
343 | .. automethod:: sge.dsp.Object.event_paused_joystick
344 |
345 | .. automethod:: sge.dsp.Object.event_paused_joystick_axis_move
346 |
347 | .. automethod:: sge.dsp.Object.event_paused_joystick_hat_move
348 |
349 | .. automethod:: sge.dsp.Object.event_paused_joystick_trackball_move
350 |
351 | .. automethod:: sge.dsp.Object.event_paused_joystick_button_press
352 |
353 | .. automethod:: sge.dsp.Object.event_paused_joystick_button_release
354 |
355 | sge.dsp Functions
356 | =================
357 |
358 | .. autofunction:: sge.dsp.list_fullscreen_modes
359 |
360 | .. autofunction:: sge.dsp.fullscreen_mode_ok
361 |
362 |
--------------------------------------------------------------------------------
/doc-src/gfx.rst:
--------------------------------------------------------------------------------
1 | *******
2 | sge.gfx
3 | *******
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.gfx
13 |
14 | sge.gfx Classes
15 | ===============
16 |
17 | sge.gfx.Color
18 | -------------
19 |
20 | .. autoclass:: sge.gfx.Color
21 |
22 | .. automethod:: sge.gfx.Color.__init__
23 |
24 | sge.gfx.Sprite
25 | --------------
26 |
27 | .. autoclass:: sge.gfx.Sprite
28 |
29 | .. automethod:: sge.gfx.Sprite.__init__
30 |
31 | sge.gfx.Sprite Methods
32 | ~~~~~~~~~~~~~~~~~~~~~~
33 |
34 | .. automethod:: sge.gfx.Sprite.append_frame
35 |
36 | .. automethod:: sge.gfx.Sprite.insert_frame
37 |
38 | .. automethod:: sge.gfx.Sprite.extend
39 |
40 | .. automethod:: sge.gfx.Sprite.delete_frame
41 |
42 | .. automethod:: sge.gfx.Sprite.get_pixel
43 |
44 | .. automethod:: sge.gfx.Sprite.get_pixels
45 |
46 | .. automethod:: sge.gfx.Sprite.draw_dot
47 |
48 | .. automethod:: sge.gfx.Sprite.draw_line
49 |
50 | .. automethod:: sge.gfx.Sprite.draw_rectangle
51 |
52 | .. automethod:: sge.gfx.Sprite.draw_ellipse
53 |
54 | .. automethod:: sge.gfx.Sprite.draw_circle
55 |
56 | .. automethod:: sge.gfx.Sprite.draw_polyline
57 |
58 | .. automethod:: sge.gfx.Sprite.draw_polygon
59 |
60 | .. automethod:: sge.gfx.Sprite.draw_sprite
61 |
62 | .. automethod:: sge.gfx.Sprite.draw_text
63 |
64 | .. automethod:: sge.gfx.Sprite.draw_shader
65 |
66 | .. automethod:: sge.gfx.Sprite.draw_erase
67 |
68 | .. automethod:: sge.gfx.Sprite.draw_clear
69 |
70 | .. automethod:: sge.gfx.Sprite.draw_lock
71 |
72 | .. automethod:: sge.gfx.Sprite.draw_unlock
73 |
74 | .. automethod:: sge.gfx.Sprite.mirror
75 |
76 | .. automethod:: sge.gfx.Sprite.flip
77 |
78 | .. automethod:: sge.gfx.Sprite.resize_canvas
79 |
80 | .. automethod:: sge.gfx.Sprite.scale
81 |
82 | .. automethod:: sge.gfx.Sprite.rotate
83 |
84 | .. automethod:: sge.gfx.Sprite.swap_color
85 |
86 | .. automethod:: sge.gfx.Sprite.copy
87 |
88 | .. automethod:: sge.gfx.Sprite.get_spritelist
89 |
90 | .. automethod:: sge.gfx.Sprite.save
91 |
92 | .. automethod:: sge.gfx.Sprite.from_tween
93 |
94 | .. automethod:: sge.gfx.Sprite.from_text
95 |
96 | .. automethod:: sge.gfx.Sprite.from_tileset
97 |
98 | .. automethod:: sge.gfx.Sprite.from_screenshot
99 |
100 | sge.gfx.Font
101 | ------------
102 |
103 | .. autoclass:: sge.gfx.Font
104 |
105 | .. automethod:: sge.gfx.Font.__init__
106 |
107 | sge.gfx.Font Methods
108 | ~~~~~~~~~~~~~~~~~~~~
109 |
110 | .. automethod:: sge.gfx.Font.get_width
111 |
112 | .. automethod:: sge.gfx.Font.get_height
113 |
114 | .. automethod:: sge.gfx.Font.from_sprite
115 |
116 | sge.gfx.BackgroundLayer
117 | -----------------------
118 |
119 | .. autoclass:: sge.gfx.BackgroundLayer
120 |
121 | .. automethod:: sge.gfx.BackgroundLayer.__init__
122 |
123 | sge.gfx.Background
124 | ------------------
125 |
126 | .. autoclass:: sge.gfx.Background
127 |
128 | .. automethod:: sge.gfx.Background.__init__
129 |
--------------------------------------------------------------------------------
/doc-src/hello_world.rst:
--------------------------------------------------------------------------------
1 | *************************
2 | Tutorial 1: Hello, world!
3 | *************************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | The easiest way to learn something new is with an example. We will
13 | start with a very basic example: the traditional "Hello, world!"
14 | program. This example will just project "Hello, world!" onto the
15 | screen.
16 |
17 | Setting Up a Project
18 | ====================
19 |
20 | First, we must create our project directory. I will use "~/hello".
21 |
22 | Next, create the game source file inside "~/hello". I am calling it
23 | "hello.py".
24 |
25 | Open hello.py so you can start editing it.
26 |
27 | Shebang
28 | -------
29 |
30 | All Python files which are supposed to be executed should start with
31 | a shebang, which is a line that tells POSIX systems (such as GNU/Linux
32 | systems, BSD, and OS X) how to execute the file. For Python 3, the
33 | version of Python we will be using, the shebang is::
34 |
35 | #!/usr/bin/env python3
36 |
37 | The shebang should be the very first line of the file. You should also
38 | make sure that the file itself uses Unix-style line endings ("\\n");
39 | this can be done in most text editors via a drop-down list available
40 | when you save, and is done by IDLE automatically. Windows-style line
41 | endings ("\\r\\n") are often interpreted wrongly in POSIX systems, which
42 | defeats the purpose of the shebang.
43 |
44 | License
45 | -------
46 |
47 | The file is copyrighted by default, so if you do not give the file a
48 | license, it will be illegal for anyone to copy and share the program.
49 | You should always choose a free/libre software license for your
50 | programs. In this example, I will use CC0, which is a public domain
51 | dedication tool. You can use CC0 if you want, or you can choose another
52 | license. You can learn about various free/libre software licenses at
53 | `http://gnu.org/licenses/ `_.
54 |
55 | The license text I am using for CC0 is::
56 |
57 | # Hello, world!
58 | #
59 | # To the extent possible under law, the author(s) have dedicated all
60 | # copyright and related and neighboring rights to this software to the
61 | # public domain worldwide. This software is distributed without any
62 | # warranty.
63 | #
64 | # You should have received a copy of the CC0 Public Domain Dedication
65 | # along with this software. If not, see
66 | # .
67 |
68 | Place your license text just under the shebang so that it is prominent.
69 |
70 | Imports
71 | -------
72 |
73 | Because we are using the SGE, we must import the ``sge`` library. Add
74 | the following line::
75 |
76 | import sge
77 |
78 | Adding Game Logic
79 | =================
80 |
81 | The Game Class
82 | --------------
83 |
84 | In SGE games, everything is controlled by a "game" object. The game
85 | object controls everything at the global level, including global events.
86 | To define global events, we need to subclass :class:`sge.dsp.Game` and
87 | create our own game class. We can just call this class ``Game``::
88 |
89 | class Game(sge.dsp.Game):
90 |
91 | def event_key_press(self, key, char):
92 | if key == 'escape':
93 | self.event_close()
94 |
95 | def event_close(self):
96 | self.end()
97 |
98 | Because our example is simple, we only need to define two events: the
99 | close event, which occurs when the OS tells the game to close (most
100 | typically when a close button is clicked on), and the key press event,
101 | which occurs when a key is pressed. We want the game to end if either
102 | the OS tells it to close or the Esc key is pressed.
103 |
104 | As you may have noticed, we define events by defining certain methods;
105 | in our case, we defined methods to override the
106 | :meth:`sge.dsp.Game.event_key_press` and
107 | :meth:`sge.dsp.Game.event_close` methods.
108 |
109 | Our definition of :meth:`event_close` is simple enough: we just call
110 | :meth:`sge.dsp.Game.end`, which ends the game. Our definition of
111 | :meth:`event_key_press` is slightly more complicated; first we have to
112 | check what key was pressed, indicated by the ``key`` argument. If the
113 | key is the Esc key, we call our :meth:`event_close` method. The reason
114 | for calling :meth:`event_close` instead of just calling :meth:`end` is
115 | simple: in the future, we might want to do more than just call
116 | :meth:`end`; perhaps, for example, we decide that we want to add a
117 | confirmation dialog before actually quitting. By connecting the key
118 | press event to the close event, if we do change what the close event
119 | does, that change will also translate to the pressing of the Esc key,
120 | avoiding needless duplication of work.
121 |
122 | The Room Class
123 | --------------
124 |
125 | Rooms are distinguished places where things happen; for example, each
126 | level in a game would typically be its own room, the title screen might
127 | be a room, the credits screen might be a room, and the options menu
128 | might be a room. In this example, we are only going to have one room,
129 | and this room is going to serve only one function: display "Hello,
130 | world!" in the center of the screen. This will be our room class::
131 |
132 | class Room(sge.dsp.Room):
133 |
134 | def event_step(self, time_passed, delta_mult):
135 | sge.game.project_text(font, "Hello, world!", sge.game.width / 2,
136 | sge.game.height / 2,
137 | color=sge.gfx.Color("black"), halign="center",
138 | valign="middle")
139 |
140 | You can see that the room class is defined very similarly to the game
141 | class. We subclass :class:`sge.dsp.Room` and add a method to override
142 | :meth:`sge.dsp.Room.event_step`, which defines the step event of our
143 | room class. The step event happens over and over again, once every
144 | "frame". You can think of frames as being like the frames in a video;
145 | each frame makes small changes to the image on the screen and then gives
146 | you the new image in a fraction of a second, providing an illusion of
147 | movement.
148 |
149 | To display "Hello, world!" onto the screen, we use
150 | :meth:`sge.dsp.Game.project_text`, which instantly displays any text we
151 | want onto the screen. :data:`sge.game` is a variable that always points
152 | to the :class:`sge.dsp.Game` object currently in use.
153 |
154 | The first argument of this method is the font to use; we don't have a
155 | font yet, but we are going to define one later and assign it to
156 | ``font``. Next is the text to display, which for us is
157 | ``"Hello, world!"``.
158 |
159 | The next arguments are the horizontal and vertical location of the text
160 | on the screen; we set these to half of the game's width and height,
161 | respectively, to place the text in the center.
162 |
163 | Now that all required arguments are defined, we are going to define the
164 | color of the text as a keyword argument, setting it explicitly to black.
165 |
166 | Finally, we define ``halign`` and ``valign`` as keyword arguments; these
167 | arguments specify the horizontal and vertical alignment of the text,
168 | respectively.
169 |
170 | You might be wondering: why do we keep doing this every frame? Can't we
171 | just do it once, since we're not changing the image? In fact, we can't.
172 | :meth:`sge.dsp.Game.project_text` shows our text, but it only does so
173 | for one frame. You can think of it as working like a movie projector:
174 | if you keep the projector on, you will continue to see the image, but as
175 | soon as the projector stops projecting the image, you can no longer see
176 | the image from the projector. :meth:`sge.dsp.Game.project_text` and
177 | other similar projection methods work the same way.
178 |
179 | Starting the Game
180 | =================
181 |
182 | If you try to run hello.py now, you will notice that nothing happens.
183 | This is because, while we defined the game logic, we didn't actually
184 | execute it.
185 |
186 | Additionally, we are still missing a resource: the font object we want
187 | to use to project text onto the screen. We need to load this resource.
188 |
189 | We are going to fix both of these problems by adding some code after our
190 | class definitions::
191 |
192 | # Create Game object
193 | Game()
194 |
195 | # Create backgrounds
196 | background = sge.gfx.Background([], sge.gfx.Color("white"))
197 |
198 | # Load fonts
199 | font = sge.gfx.Font()
200 |
201 | # Create rooms
202 | sge.game.start_room = Room(background=background)
203 |
204 | if __name__ == '__main__':
205 | sge.game.start()
206 |
207 | First, we create a :class:`sge.dsp.Game` object; we don't need to store
208 | it in anything since it is automatically stored in :data:`sge.game`.
209 |
210 | Second, we create a :class:`sge.gfx.Background` object to specify what
211 | the background looks like. We make our background all white, with no
212 | layers. (Layers are used to give backgrounds more than a solid color,
213 | which we don't need.)
214 |
215 | Third, we create our font. We don't really care what this font looks
216 | like, so we allow the SGE to pick a font. If you do care what font is
217 | used, you can pass the name of a font onto the ``name`` keyword
218 | argument.
219 |
220 | Fourth, we create a room. The only argument we pass is the background
221 | argument; we set this to the background we created earlier. Since it is
222 | the room that we are going to start the game with, we need to assign
223 | this room to the special attribute, :attr:`sge.game.start_room`, which
224 | indicates the room that the game starts with.
225 |
226 | Finally, with everything in place, we call the
227 | :meth:`sge.dsp.Game.start` method of our game object. This executes all
228 | the game logic we defined earlier. However, we only do this if the
229 | special Python variable, :data:`__name__`, is set to ``"__main__"``,
230 | which means that the current module is the main module, i.e. was
231 | executed rather than imported. It is a good practice to include this
232 | distinction between being executed and being imported in all of your
233 | Python scripts.
234 |
235 | The Final Result
236 | ================
237 |
238 | That's it! If you execute the script now, you will see a white screen
239 | with black text in the center reading "Hello, world!" Pressing the Esc
240 | key or clicking on the close button in the window will close the
241 | program. Congratulations on writing your first SGE program!
242 |
243 | This is the completed Hello World program::
244 |
245 | #!/usr/bin/env python3
246 |
247 | # Hello, world!
248 | #
249 | # To the extent possible under law, the author(s) have dedicated all
250 | # copyright and related and neighboring rights to this software to the
251 | # public domain worldwide. This software is distributed without any
252 | # warranty.
253 | #
254 | # You should have received a copy of the CC0 Public Domain Dedication
255 | # along with this software. If not, see
256 | # .
257 |
258 | import sge
259 |
260 |
261 | class Game(sge.dsp.Game):
262 |
263 | def event_key_press(self, key, char):
264 | if key == 'escape':
265 | self.event_close()
266 |
267 | def event_close(self):
268 | self.end()
269 |
270 |
271 | class Room(sge.dsp.Room):
272 |
273 | def event_step(self, time_passed, delta_mult):
274 | sge.game.project_text(font, "Hello, world!", sge.game.width / 2,
275 | sge.game.height / 2,
276 | color=sge.gfx.Color("black"), halign="center",
277 | valign="middle")
278 |
279 |
280 | # Create Game object
281 | Game()
282 |
283 | # Create backgrounds
284 | background = sge.gfx.Background([], sge.gfx.Color("white"))
285 |
286 | # Load fonts
287 | font = sge.gfx.Font()
288 |
289 | # Create rooms
290 | sge.game.start_room = Room(background=background)
291 |
292 | if __name__ == '__main__':
293 | sge.game.start()
294 |
--------------------------------------------------------------------------------
/doc-src/index.rst:
--------------------------------------------------------------------------------
1 | ***********************************
2 | Seclusion Game Engine documentation
3 | ***********************************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. toctree::
11 | :maxdepth: 1
12 |
13 | sge
14 | hello_world
15 | pong
16 | pong_better
17 | input
18 | dsp
19 | gfx
20 | snd
21 | collision
22 | joystick
23 | keyboard
24 | mouse
25 | s
26 |
27 | Indices and tables
28 | ==================
29 |
30 | * :ref:`genindex`
31 | * :ref:`modindex`
32 | * :ref:`search`
33 |
34 |
--------------------------------------------------------------------------------
/doc-src/input.rst:
--------------------------------------------------------------------------------
1 | *********
2 | sge.input
3 | *********
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.input
13 |
14 | Input Event Classes
15 | ===================
16 |
17 | .. autoclass:: sge.input.KeyPress
18 |
19 | .. autoclass:: sge.input.KeyRelease
20 |
21 | .. autoclass:: sge.input.MouseMove
22 |
23 | .. autoclass:: sge.input.MouseButtonPress
24 |
25 | .. autoclass:: sge.input.MouseButtonRelease
26 |
27 | .. autoclass:: sge.input.MouseWheelMove
28 |
29 | .. autoclass:: sge.input.JoystickAxisMove
30 |
31 | .. autoclass:: sge.input.JoystickHatMove
32 |
33 | .. autoclass:: sge.input.JoystickTrackballMove
34 |
35 | .. autoclass:: sge.input.JoystickButtonPress
36 |
37 | .. autoclass:: sge.input.JoystickButtonRelease
38 |
39 | .. autoclass:: sge.input.KeyboardFocusGain
40 |
41 | .. autoclass:: sge.input.KeyboardFocusLose
42 |
43 | .. autoclass:: sge.input.MouseFocusGain
44 |
45 | .. autoclass:: sge.input.MouseFocusLose
46 |
47 | .. autoclass:: sge.input.WindowResize
48 |
49 | .. autoclass:: sge.input.QuitRequest
50 |
--------------------------------------------------------------------------------
/doc-src/joystick.rst:
--------------------------------------------------------------------------------
1 | ************
2 | sge.joystick
3 | ************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.joystick
13 |
14 | sge.joystick Functions
15 | ======================
16 |
17 | .. autofunction:: sge.joystick.refresh
18 |
19 | .. autofunction:: sge.joystick.get_axis
20 |
21 | .. autofunction:: sge.joystick.get_hat_x
22 |
23 | .. autofunction:: sge.joystick.get_hat_y
24 |
25 | .. autofunction:: sge.joystick.get_pressed
26 |
27 | .. autofunction:: sge.joystick.get_joysticks
28 |
29 | .. autofunction:: sge.joystick.get_name
30 |
31 | .. autofunction:: sge.joystick.get_id
32 |
33 | .. autofunction:: sge.joystick.get_axes
34 |
35 | .. autofunction:: sge.joystick.get_hats
36 |
37 | .. autofunction:: sge.joystick.get_trackballs
38 |
39 | .. autofunction:: sge.joystick.get_buttons
40 |
--------------------------------------------------------------------------------
/doc-src/keyboard.rst:
--------------------------------------------------------------------------------
1 | ************
2 | sge.keyboard
3 | ************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.keyboard
13 |
14 | sge.keyboard Functions
15 | ======================
16 |
17 | .. autofunction:: sge.keyboard.get_pressed
18 |
19 | .. autofunction:: sge.keyboard.get_modifier
20 |
21 | .. autofunction:: sge.keyboard.get_focused
22 |
23 | .. autofunction:: sge.keyboard.set_repeat
24 |
25 | .. autofunction:: sge.keyboard.get_repeat_enabled
26 |
27 | .. autofunction:: sge.keyboard.get_repeat_interval
28 |
29 | .. autofunction:: sge.keyboard.get_repeat_delay
30 |
--------------------------------------------------------------------------------
/doc-src/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/doc-src/mouse.rst:
--------------------------------------------------------------------------------
1 | *********
2 | sge.mouse
3 | *********
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.mouse
13 |
14 | sge.mouse Functions
15 | ===================
16 |
17 | .. autofunction:: sge.mouse.get_pressed
18 |
19 | .. autofunction:: sge.mouse.get_x
20 |
21 | .. autofunction:: sge.mouse.get_y
22 |
23 | .. autofunction:: sge.mouse.set_x
24 |
25 | .. autofunction:: sge.mouse.set_y
26 |
--------------------------------------------------------------------------------
/doc-src/s.rst:
--------------------------------------------------------------------------------
1 | *****
2 | sge.s
3 | *****
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.s
13 |
--------------------------------------------------------------------------------
/doc-src/sge.rst:
--------------------------------------------------------------------------------
1 | ****************
2 | SGE Fundamentals
3 | ****************
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge
13 |
--------------------------------------------------------------------------------
/doc-src/snd.rst:
--------------------------------------------------------------------------------
1 | *******
2 | sge.snd
3 | *******
4 |
5 | .. This file has been dedicated to the public domain, to the extent
6 | possible under applicable law, via CC0. See
7 | http://creativecommons.org/publicdomain/zero/1.0/ for more
8 | information. This file is offered as-is, without any warranty.
9 |
10 | .. contents::
11 |
12 | .. automodule:: sge.snd
13 |
14 | sge.snd Classes
15 | ===============
16 |
17 | sge.snd.Sound
18 | -------------
19 |
20 | .. autoclass:: sge.snd.Sound
21 |
22 | .. automethod:: sge.snd.Sound.__init__
23 |
24 | sge.snd.Sound Methods
25 | ~~~~~~~~~~~~~~~~~~~~~
26 |
27 | .. automethod:: sge.snd.Sound.play
28 |
29 | .. automethod:: sge.snd.Sound.stop
30 |
31 | .. automethod:: sge.snd.Sound.pause
32 |
33 | .. automethod:: sge.snd.Sound.unpause
34 |
35 | sge.snd.Music
36 | -------------
37 |
38 | .. autoclass:: sge.snd.Music
39 |
40 | .. automethod:: sge.snd.Music.__init__
41 |
42 | sge.snd.Music Methods
43 | ~~~~~~~~~~~~~~~~~~~~~
44 |
45 | .. automethod:: sge.snd.Music.play
46 |
47 | .. automethod:: sge.snd.Music.queue
48 |
49 | .. automethod:: sge.snd.Music.stop
50 |
51 | .. automethod:: sge.snd.Music.pause
52 |
53 | .. automethod:: sge.snd.Music.unpause
54 |
55 | .. automethod:: sge.snd.Music.clear_queue
56 |
57 | sge.snd Functions
58 | =================
59 |
60 | .. autofunction:: sge.snd.stop_all
61 |
62 |
--------------------------------------------------------------------------------
/examples/cc0-1.0.txt:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/examples/circle_popper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Circle Popper
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 |
23 |
24 | class glob(object):
25 |
26 | circle_sprite = None
27 | circle_pop_sprite = None
28 | font = None
29 | pop_sound = None
30 | music = None
31 |
32 |
33 | class Game(sge.dsp.Game):
34 |
35 | def event_step(self, time_passed, delta_mult):
36 | self.fps_time += time_passed
37 | self.fps_frames += 1
38 | if self.fps_time >= 250:
39 | self.fps_text = str(round((1000 * self.fps_frames) /
40 | self.fps_time))
41 | self.fps_time = 0
42 | self.fps_frames = 0
43 |
44 | self.project_text(glob.font, self.fps_text, self.width - 8, 8,
45 | color=sge.gfx.Color("#000"), halign="right")
46 | self.project_polyline([(428.2, 328), (424, 460.1), (460, 340.9)],
47 | sge.gfx.Color("red"), thickness=3.1)
48 |
49 | def event_key_press(self, key, char):
50 | if key == 'escape':
51 | self.end()
52 |
53 | def event_close(self):
54 | self.end()
55 |
56 |
57 | class Circle(sge.dsp.Object):
58 |
59 | def __init__(self, x, y):
60 | super(Circle, self).__init__(x, y, 5, sprite=glob.circle_sprite,
61 | collision_precise=True)
62 |
63 | def event_create(self):
64 | self.image_alpha = 200
65 | if self.collision(sge.game.mouse):
66 | self.image_blend = sge.gfx.Color('#ff0000')
67 | else:
68 | self.image_blend = sge.gfx.Color('blue')
69 |
70 | def event_mouse_move(self, x, y):
71 | if self.collision(sge.game.mouse):
72 | self.image_blend = sge.gfx.Color("red")
73 | else:
74 | self.image_blend = sge.gfx.Color((0, 0, 255))
75 |
76 | def event_mouse_button_press(self, button):
77 | if button == 'left':
78 | if self.collision(sge.game.mouse):
79 | self.destroy()
80 |
81 | def event_destroy(self):
82 | pop = CirclePop(self.x, self.y)
83 | pop.image_blend = self.image_blend
84 | sge.game.current_room.add(pop)
85 | assert glob.pop_sound is not None
86 | glob.pop_sound.play()
87 |
88 |
89 | class CirclePop(sge.dsp.Object):
90 |
91 | def __init__(self, x, y):
92 | super(CirclePop, self).__init__(x, y, 5, sprite=glob.circle_pop_sprite,
93 | tangible=False)
94 |
95 | def event_animation_end(self):
96 | self.destroy()
97 |
98 | def event_destroy(self):
99 | circle = Circle(random.randint(0, sge.game.width),
100 | random.randint(0, sge.game.height))
101 | sge.game.current_room.add(circle)
102 |
103 |
104 | class Room(sge.dsp.Room):
105 |
106 | def event_room_start(self):
107 | self.shake = 0
108 | self.event_room_resume()
109 |
110 | def event_room_resume(self):
111 | glob.music.play(loops=None)
112 |
113 | def event_step(self, time_passed, delta_mult):
114 | self.project_rectangle(5, 5, 3, 32, 32, fill=sge.gfx.Color("red"),
115 | outline=sge.gfx.Color("green"),
116 | outline_thickness=3.4)
117 | self.project_ellipse(16, 100, 3, 84, 64, fill=sge.gfx.Color("yellow"),
118 | outline=sge.gfx.Color("fuchsia"),
119 | outline_thickness=3.9, anti_alias=True)
120 | self.project_line(64, 64, 78, 100, 3, sge.gfx.Color("black"),
121 | thickness=2.2, anti_alias=True)
122 | self.project_dot(90, 32, 3, sge.gfx.Color("maroon"))
123 | self.project_dot(91, 32, 3, sge.gfx.Color("maroon"))
124 | self.project_dot(92, 32, 3, sge.gfx.Color("maroon"))
125 | self.project_dot(93, 32, 3, sge.gfx.Color("maroon"))
126 | self.project_dot(90, 33, 3, sge.gfx.Color("maroon"))
127 | self.project_dot(91, 33, 3, sge.gfx.Color("maroon"))
128 | self.project_dot(92, 33, 3, sge.gfx.Color("maroon"))
129 | self.project_dot(90, 34, 3, sge.gfx.Color("maroon"))
130 | self.project_dot(91, 34, 3, sge.gfx.Color("maroon"))
131 | self.project_dot(90, 35, 3, sge.gfx.Color("maroon"))
132 | self.project_polygon([(128.2, 128), (124, 160.1), (160, 140.9)], 3,
133 | fill=sge.gfx.Color("gray"),
134 | outline=sge.gfx.Color("red"),
135 | outline_thickness=3, anti_alias=True)
136 | self.project_polyline([(228.2, 128), (224, 260.1), (260, 140.9)], 5,
137 | sge.gfx.Color("red"), thickness=3.1,
138 | anti_alias=True)
139 | self.project_circle(500, 100, 3, 30,
140 | fill=sge.gfx.Color("gray"),
141 | outline=sge.gfx.Color("maroon"),
142 | outline_thickness=10, anti_alias=True)
143 | text = "I am amazing text!\n\nYaaaaaaaaaaay~!"
144 | self.project_text(glob.font, text, 320, 0, 3,
145 | color=sge.gfx.Color("black"), halign="center")
146 | self.project_text(glob.font, text, 320, 80, 3,
147 | color=sge.gfx.Color("white"), halign="center",
148 | outline=sge.gfx.Color("black"),
149 | outline_thickness=30.4)
150 |
151 | if sge.keyboard.get_pressed("left"):
152 | self.views[0].xport -= 1
153 | if sge.keyboard.get_pressed("right"):
154 | self.views[0].xport += 1
155 | if sge.keyboard.get_pressed("up"):
156 | self.views[0].yport -= 1
157 | if sge.keyboard.get_pressed("down"):
158 | self.views[0].yport += 1
159 |
160 | def event_alarm(self, alarm_id):
161 | if alarm_id == "shake":
162 | self.views[0].xport += random.uniform(-2, 2)
163 | self.views[0].yport += random.uniform(-2, 2)
164 | self.shake -= 1
165 | if self.shake > 0:
166 | self.alarms["shake"] = 1
167 | else:
168 | self.views[0].xport = 0
169 | self.views[0].yport = 0
170 | elif alarm_id == "shake_down":
171 | self.views[0].yport = 3
172 | self.alarms["shake_up"] = 1
173 | elif alarm_id == "shake_up":
174 | self.views[0].yport = 0
175 | self.shake -= 1
176 | if self.shake > 0:
177 | self.alarms["shake_down"] = 1
178 |
179 | def event_key_press(self, key, char):
180 | if key in ("ctrl_left", "ctrl_right"):
181 | self.shake = 20
182 | self.event_alarm("shake_down")
183 | elif key in ("shift_left", "shift_right"):
184 | self.shake = 20
185 | self.event_alarm("shake")
186 |
187 |
188 | def invert(x, y, red, green, blue, alpha):
189 | return 255 - red, 255 - green, 255 - blue, alpha
190 |
191 |
192 | def main():
193 | # Create Game object
194 | game = Game(delta=True, delta_max=4800, collision_events_enabled=False)
195 |
196 | # Load sprites
197 | glob.circle_sprite = sge.gfx.Sprite('circle', DATA, width=64, height=64,
198 | origin_x=32, origin_y=32)
199 | glob.circle_pop_sprite = sge.gfx.Sprite('circle_pop', DATA, width=64,
200 | height=64, origin_x=32,
201 | origin_y=32, fps=60)
202 | fence_sprite = sge.gfx.Sprite('fence', DATA)
203 | fence_sprite.draw_shader(0, 0, fence_sprite.width, fence_sprite.height,
204 | invert)
205 |
206 | # Load backgrounds
207 | layers = [sge.gfx.BackgroundLayer(fence_sprite, 0, 380, 0,
208 | repeat_left=True, repeat_right=True)]
209 | background = sge.gfx.Background(layers, sge.gfx.Color(0xffffff))
210 |
211 | # Load fonts
212 | glob.font = sge.gfx.Font('Liberation Serif', 20)
213 |
214 | # Load sounds
215 | glob.pop_sound = sge.snd.Sound(os.path.join(DATA, 'pop.ogg'))
216 |
217 | # Load music
218 | glob.music = sge.snd.Music(os.path.join(DATA, 'WhereWasI.ogg'))
219 |
220 | # Create objects
221 | circle = Circle(game.width // 2, game.height // 2)
222 | circle2 = Circle(22, 48)
223 | circle3 = Circle(486, 301)
224 | circle4 = Circle(50, 400)
225 | objects = [circle, circle2, circle3, circle4]
226 |
227 | # Create view
228 | views = [sge.dsp.View(0, 0)]
229 |
230 | # Create rooms
231 | game.start_room = Room(objects, views=views, background=background)
232 |
233 | game.fps_time = 0
234 | game.fps_frames = 0
235 | game.fps_text = ""
236 |
237 | game.start()
238 |
239 |
240 | if __name__ == '__main__':
241 | main()
242 |
--------------------------------------------------------------------------------
/examples/data/LICENSES:
--------------------------------------------------------------------------------
1 | This file lists the licenses, authors, and sources for all the
2 | non-functional data files found in this directory.
3 |
4 | This file itself has been dedicated to the public domain, to the extent
5 | possible under applicable law, via CC0. See
6 | http://creativecommons.org/publicdomain/zero/1.0/ for more
7 | information. This file is offered as-is, without any warranty.
8 |
9 | ========================================================================
10 |
11 | circle.png
12 | circle_pop-0.png
13 | circle_pop-1.png
14 | circle_pop-2.png
15 | circle_pop-3.png
16 | circle_pop-4.png
17 | circle_pop-5.png
18 | circle_pop-6.png
19 | circle_pop-7.png
20 | circle_pop-8.png
21 | circle_pop-9.png
22 | circle_pop-10.png
23 | circle_pop-11.png
24 | circle_pop-12.png
25 | fence.png
26 | light.png
27 | rotator.png
28 | bounce.wav
29 | bounce_wall.wav
30 | score.wav
31 |
32 | Author: Layla Marchant
33 | License: CC0
34 |
35 | ------------------------------------------------------------------------
36 |
37 | pop.ogg
38 |
39 | Author: kddekadenz
40 | License: CC0
41 | Source: http://opengameart.org/content/stove-switch
42 |
43 | ------------------------------------------------------------------------
44 |
45 | WhereWasI.ogg
46 |
47 | Author: yd
48 | License: CC0
49 | Source: http://opengameart.org/content/where-was-i
50 |
--------------------------------------------------------------------------------
/examples/data/WhereWasI.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/WhereWasI.ogg
--------------------------------------------------------------------------------
/examples/data/bounce.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/bounce.wav
--------------------------------------------------------------------------------
/examples/data/bounce_wall.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/bounce_wall.wav
--------------------------------------------------------------------------------
/examples/data/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-0.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-1.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-10.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-11.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-12.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-2.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-3.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-4.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-5.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-6.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-7.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-8.png
--------------------------------------------------------------------------------
/examples/data/circle_pop-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/circle_pop-9.png
--------------------------------------------------------------------------------
/examples/data/fence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/fence.png
--------------------------------------------------------------------------------
/examples/data/pop.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/pop.ogg
--------------------------------------------------------------------------------
/examples/data/rotator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/rotator.png
--------------------------------------------------------------------------------
/examples/data/score.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/python-sge/sge/0baf62526d505506185390a21387e204c1319c50/examples/data/score.wav
--------------------------------------------------------------------------------
/examples/jstest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Joystick Tester
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import sge
16 |
17 | TITLE_HEIGHT = 48
18 | UPDATE_DELAY = 10
19 |
20 |
21 | class glob(object):
22 |
23 | js_selection_sprite = None
24 | js_state_sprite = None
25 | name_font = None
26 | state_font = None
27 |
28 |
29 | class Game(sge.dsp.Game):
30 |
31 | def event_key_press(self, key, char):
32 | if key == 'escape':
33 | self.event_close()
34 |
35 | def event_close(self):
36 | self.end()
37 |
38 |
39 | class Room(sge.dsp.Room):
40 |
41 | def set_joystick(self):
42 | self.joystick_axes = []
43 | for i in range(sge.joystick.get_axes(self.current_joystick)):
44 | self.joystick_axes.append(sge.joystick.get_axis(
45 | self.current_joystick, i))
46 |
47 | self.joystick_hats = []
48 | for i in range(sge.joystick.get_hats(self.current_joystick)):
49 | self.joystick_hats.append((
50 | sge.joystick.get_hat_x(self.current_joystick, i),
51 | sge.joystick.get_hat_y(self.current_joystick, i)))
52 |
53 | self.joystick_balls = []
54 | for i in range(sge.joystick.get_trackballs(self.current_joystick)):
55 | self.joystick_balls.append(0)
56 |
57 | self.joystick_buttons = []
58 | for i in range(sge.joystick.get_buttons(self.current_joystick)):
59 | self.joystick_buttons.append(sge.joystick.get_pressed(
60 | self.current_joystick, i))
61 |
62 | glob.js_selection_sprite.draw_clear()
63 |
64 | title_text = 'Joystick {0} ("{1}")'.format(
65 | sge.joystick.get_id(self.current_joystick),
66 | sge.joystick.get_name(self.current_joystick))
67 |
68 | x = glob.js_selection_sprite.width / 2
69 | y = glob.js_selection_sprite.height / 2
70 | glob.js_selection_sprite.draw_text(
71 | glob.name_font, title_text, x, y, color=sge.gfx.Color("white"),
72 | halign="center", valign="middle")
73 |
74 | self.print_state()
75 |
76 | def print_state(self):
77 | lines = []
78 |
79 | for i in range(len(self.joystick_axes)):
80 | lines.append("Axis {0}: {1}".format(i, self.joystick_axes[i]))
81 |
82 | for i in range(len(self.joystick_hats)):
83 | lines.append("HAT {0}: {1}".format(
84 | i, "{0} x {1}".format(*self.joystick_hats[i])))
85 |
86 | for i in range(len(self.joystick_balls)):
87 | lines.append("Trackball {0}: {1}".format(
88 | i, "{0} x {1}".format(*self.joystick_balls[i])))
89 |
90 | for i in range(len(self.joystick_buttons)):
91 | lines.append("Button {0}: {1}".format(
92 | i, "Pressed" if self.joystick_buttons[i] else "Released"))
93 |
94 | left_text = '\n'.join([lines[i] for i in range(0, len(lines), 2)])
95 | right_text = '\n'.join([lines[i] for i in range(1, len(lines), 2)])
96 |
97 | glob.js_state_sprite.draw_clear()
98 | glob.js_state_sprite.draw_text(glob.state_font, left_text, 0, 0,
99 | color=sge.gfx.Color("white"))
100 | x = glob.js_state_sprite.width / 2
101 | glob.js_state_sprite.draw_text(glob.state_font, right_text, x, 0,
102 | color=sge.gfx.Color("white"))
103 |
104 | def event_room_start(self):
105 | self.current_joystick = 0
106 | self.changed = False
107 | self.ball_nonzero = False
108 | self.set_joystick()
109 |
110 | def event_step(self, time_passed, delta_mult):
111 | if self.changed:
112 | self.changed = False
113 | self.print_state()
114 |
115 | if self.ball_nonzero:
116 | # Reset ball motion to 0
117 | for i in range(len(self.joystick_balls)):
118 | self.joystick_balls[i] = (0, 0)
119 |
120 | self.changed = True
121 | self.ball_nonzero = False
122 |
123 | def event_key_press(self, key, char):
124 | if key == "left":
125 | num = sge.joystick.get_joysticks()
126 | if num:
127 | self.current_joystick -= 1
128 | self.current_joystick %= num
129 | self.set_joystick()
130 | elif key == "right":
131 | num = sge.joystick.get_joysticks()
132 | if num:
133 | self.current_joystick += 1
134 | self.current_joystick %= num
135 | self.set_joystick()
136 | elif key == "space":
137 | sge.joystick.refresh()
138 | self.set_joystick()
139 |
140 | def event_joystick_axis_move(self, js_name, js_id, axis, value):
141 | if (self.current_joystick in (js_name, js_id) and
142 | axis < len(self.joystick_axes)):
143 | self.joystick_axes[axis] = value
144 |
145 | self.changed = True
146 |
147 | def event_joystick_hat_move(self, js_name, js_id, hat, x, y):
148 | if (self.current_joystick in (js_name, js_id) and
149 | hat < len(self.joystick_hats)):
150 | self.joystick_hats[hat] = (x, y)
151 |
152 | self.changed = True
153 |
154 | def event_joystick_trackball_move(self, js_name, js_id, ball, x, y):
155 | if (self.current_joystick in (js_name, js_id) and
156 | ball < len(self.joystick_balls)):
157 | self.joystick_balls[ball] = (x, y)
158 |
159 | self.changed = True
160 | self.ball_nonzero = True
161 |
162 | def event_joystick_button_press(self, js_name, js_id, button):
163 | if (self.current_joystick in (js_name, js_id) and
164 | button < len(self.joystick_buttons)):
165 | self.joystick_buttons[button] = True
166 |
167 | self.changed = True
168 |
169 | def event_joystick_button_release(self, js_name, js_id, button):
170 | if (self.current_joystick in (js_name, js_id) and
171 | button < len(self.joystick_buttons)):
172 | self.joystick_buttons[button] = False
173 |
174 | self.changed = True
175 |
176 |
177 | def main():
178 | # Create Game object
179 | Game(width=640, height=480)
180 |
181 | # Load sprites
182 | glob.js_selection_sprite = sge.gfx.Sprite(width=sge.game.width,
183 | height=TITLE_HEIGHT)
184 | glob.js_state_sprite = sge.gfx.Sprite(
185 | width=sge.game.width, height=(sge.game.height - TITLE_HEIGHT))
186 |
187 | # Load fonts
188 | glob.name_font = sge.gfx.Font('Liberation Sans', size=18)
189 | glob.state_font = sge.gfx.Font('Liberation Sans', size=14)
190 |
191 | # Create objects
192 | selection_object = sge.dsp.Object(0, 0, sprite=glob.js_selection_sprite,
193 | tangible=False)
194 | state_object = sge.dsp.Object(0, TITLE_HEIGHT,
195 | sprite=glob.js_state_sprite,
196 | tangible=False)
197 | objects = (selection_object, state_object)
198 |
199 | # Create rooms
200 | sge.game.start_room = Room(objects)
201 |
202 | sge.game.start()
203 |
204 |
205 | if __name__ == '__main__':
206 | main()
207 |
--------------------------------------------------------------------------------
/examples/large_room.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Large Room Example
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 |
23 |
24 | class Game(sge.dsp.Game):
25 | def event_key_press(self, key, char):
26 | if key == 'escape':
27 | self.end()
28 | elif key == "backspace":
29 | view = self.current_room.views[0]
30 | view.width = view.wport
31 | view.height = view.hport
32 |
33 | def event_close(self):
34 | self.end()
35 |
36 |
37 | class Circle(sge.dsp.Object):
38 | def __init__(self, x, y):
39 | super(Circle, self).__init__(x, y, 1, sprite=circle_sprite,
40 | collision_precise=True,
41 | image_blend=sge.gfx.Color("red"),
42 | image_alpha=128)
43 |
44 | def event_step(self, time_passed, delta_mult):
45 | left_key = 'left'
46 | right_key = 'right'
47 | up_key = 'up'
48 | down_key = 'down'
49 | self.xvelocity = (sge.keyboard.get_pressed(right_key) -
50 | sge.keyboard.get_pressed(left_key))
51 | self.yvelocity = (sge.keyboard.get_pressed(down_key) -
52 | sge.keyboard.get_pressed(up_key))
53 |
54 | # Limit the circles to inside the room.
55 | if self.bbox_left < 0:
56 | self.bbox_left = 0
57 | elif self.bbox_right >= sge.game.current_room.width:
58 | self.bbox_right = sge.game.current_room.width - 1
59 | if self.bbox_top < 0:
60 | self.bbox_top = 0
61 | elif self.bbox_bottom >= sge.game.current_room.height:
62 | self.bbox_bottom = sge.game.current_room.height - 1
63 |
64 | # Set view
65 | my_view = sge.game.current_room.views[0]
66 | zoom_add = (sge.keyboard.get_pressed("hyphen") -
67 | sge.keyboard.get_pressed("equals"))
68 | my_view.width += zoom_add
69 | my_view.width = max(48, min(my_view.width, sge.game.current_room.width))
70 | my_view.height = my_view.width
71 | my_view.x = self.x - (my_view.width // 2)
72 | my_view.y = self.y - (my_view.height // 2)
73 |
74 |
75 | def main():
76 | global circle_sprite
77 |
78 | # Create Game object
79 | Game(width=240, height=240, scale_method="smooth",
80 | collision_events_enabled=False)
81 |
82 | # Load sprites
83 | circle_sprite = sge.gfx.Sprite('circle', DATA, width=32, height=32,
84 | origin_x=16, origin_y=16)
85 | fence = sge.gfx.Sprite('fence', DATA)
86 |
87 | # Load backgrounds
88 | layers = [sge.gfx.BackgroundLayer(fence, 0, 0, 0, repeat_left=True,
89 | repeat_right=True, repeat_up=True,
90 | repeat_down=True)]
91 | background = sge.gfx.Background(layers, sge.gfx.Color('white'))
92 |
93 | # Create objects
94 | circle = Circle(random.randrange(0, 640), random.randrange(0, 480))
95 | objects = [circle]
96 |
97 | # Create views
98 | views = [sge.dsp.View(0, 0, 0, 0, 240, 240, 240, 240)]
99 |
100 | # Create rooms
101 | sge.game.start_room = sge.dsp.Room(objects, width=640, height=640,
102 | views=views, background=background)
103 |
104 | sge.game.start()
105 |
106 |
107 | if __name__ == '__main__':
108 | main()
109 |
110 |
--------------------------------------------------------------------------------
/examples/pong.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Pong Example
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 | PADDLE_XOFFSET = 32
23 | PADDLE_SPEED = 4
24 | PADDLE_VERTICAL_FORCE = 1 / 12
25 | BALL_START_SPEED = 2
26 | BALL_ACCELERATION = 0.2
27 | BALL_MAX_SPEED = 15
28 | POINTS_TO_WIN = 10
29 | TEXT_OFFSET = 16
30 |
31 | game_in_progress = True
32 |
33 |
34 | class Game(sge.dsp.Game):
35 |
36 | def event_step(self, time_passed, delta_mult):
37 | self.project_sprite(hud_sprite, 0, self.width / 2, 0)
38 |
39 | self.fps_time += time_passed
40 | self.fps_frames += 1
41 | if self.fps_time >= 250:
42 | self.fps_text = str(round((1000 * self.fps_frames) /
43 | self.fps_time))
44 | self.fps_time = 0
45 | self.fps_frames = 0
46 |
47 | self.project_text(hud_font, self.fps_text, 8, 8,
48 | color=sge.gfx.Color("gray"))
49 |
50 | def event_key_press(self, key, char):
51 | global game_in_progress
52 |
53 | if key == 'f8':
54 | sge.gfx.Sprite.from_screenshot().save('screenshot.jpg')
55 | elif key == 'f11':
56 | self.fullscreen = not self.fullscreen
57 | elif key == 'escape':
58 | self.event_close()
59 | elif key in ('p', 'enter'):
60 | if game_in_progress:
61 | self.pause()
62 | else:
63 | game_in_progress = True
64 | create_room().start()
65 |
66 | def event_close(self):
67 | self.end()
68 |
69 | def event_paused_key_press(self, key, char):
70 | if key == 'escape':
71 | # This allows the player to still exit while the game is
72 | # paused, rather than having to unpause first.
73 | self.event_close()
74 | else:
75 | self.unpause()
76 |
77 | def event_paused_close(self):
78 | # This allows the player to still exit while the game is paused,
79 | # rather than having to unpause first.
80 | self.event_close()
81 |
82 |
83 | class Player(sge.dsp.Object):
84 |
85 | score = 0
86 |
87 | def __init__(self, player):
88 | if player == 1:
89 | self.joystick = 0
90 | self.up_key = "w"
91 | self.down_key = "s"
92 | x = PADDLE_XOFFSET
93 | self.hit_direction = 1
94 | else:
95 | self.joystick = 1
96 | self.up_key = "up"
97 | self.down_key = "down"
98 | x = sge.game.width - PADDLE_XOFFSET
99 | self.hit_direction = -1
100 |
101 | y = sge.game.height / 2
102 | super(Player, self).__init__(x, y, sprite=paddle_sprite,
103 | checks_collisions=False)
104 |
105 | def event_create(self):
106 | self.score = 0
107 | refresh_hud()
108 | self.trackball_motion = 0
109 |
110 | def event_step(self, time_passed, delta_mult):
111 | # Movement
112 | key_motion = (sge.keyboard.get_pressed(self.down_key) -
113 | sge.keyboard.get_pressed(self.up_key))
114 | axis_motion = sge.joystick.get_axis(self.joystick, 1)
115 |
116 | if (abs(axis_motion) > abs(key_motion) and
117 | abs(axis_motion) > abs(self.trackball_motion)):
118 | self.yvelocity = axis_motion * PADDLE_SPEED
119 | elif abs(self.trackball_motion) > abs(key_motion):
120 | self.yvelocity = self.trackball_motion * PADDLE_SPEED
121 | else:
122 | self.yvelocity = key_motion * PADDLE_SPEED
123 |
124 | self.trackball_motion = 0
125 |
126 | # Keep the paddle inside the window
127 | if self.bbox_top < 0:
128 | self.bbox_top = 0
129 | elif self.bbox_bottom > sge.game.current_room.height:
130 | self.bbox_bottom = sge.game.current_room.height
131 |
132 | def event_joystick_trackball_move(self, joystick, ball, x, y):
133 | if joystick == self.joystick:
134 | self.trackball_motion += y
135 |
136 |
137 | class Ball(sge.dsp.Object):
138 |
139 | def __init__(self):
140 | x = sge.game.width / 2
141 | y = sge.game.height / 2
142 | super(Ball, self).__init__(x, y, sprite=ball_sprite)
143 |
144 | def event_create(self):
145 | self.serve()
146 |
147 | def event_step(self, time_passed, delta_mult):
148 | # Scoring
149 | if self.bbox_right < 0:
150 | player2.score += 1
151 | refresh_hud()
152 | score_sound.play()
153 | self.serve(-1)
154 | elif self.bbox_left > sge.game.current_room.width:
155 | player1.score += 1
156 | refresh_hud()
157 | score_sound.play()
158 | self.serve(1)
159 |
160 | # Bouncing off of the edges
161 | if self.bbox_bottom > sge.game.current_room.height:
162 | self.bbox_bottom = sge.game.current_room.height
163 | self.yvelocity = -abs(self.yvelocity)
164 | bounce_wall_sound.play()
165 | elif self.bbox_top < 0:
166 | self.bbox_top = 0
167 | self.yvelocity = abs(self.yvelocity)
168 | bounce_wall_sound.play()
169 |
170 | def event_collision(self, other, xdirection, ydirection):
171 | if isinstance(other, Player):
172 | if other.hit_direction == 1:
173 | self.bbox_left = other.bbox_right + 1
174 | else:
175 | self.bbox_right = other.bbox_left - 1
176 |
177 | self.xvelocity = min(abs(self.xvelocity) + BALL_ACCELERATION,
178 | BALL_MAX_SPEED) * other.hit_direction
179 | self.yvelocity += (self.y - other.y) * PADDLE_VERTICAL_FORCE
180 | bounce_sound.play()
181 |
182 | def serve(self, direction=None):
183 | global game_in_progress
184 |
185 | if direction is None:
186 | direction = random.choice([-1, 1])
187 |
188 | self.x = self.xstart
189 | self.y = self.ystart
190 |
191 | if (player1.score < POINTS_TO_WIN and
192 | player2.score < POINTS_TO_WIN):
193 | # Next round
194 | self.xvelocity = BALL_START_SPEED * direction
195 | self.yvelocity = 0
196 | else:
197 | # Game Over!
198 | self.xvelocity = 0
199 | self.yvelocity = 0
200 | hud_sprite.draw_clear()
201 | x = hud_sprite.width / 2
202 | p1text = "WIN" if player1.score > player2.score else "LOSE"
203 | p2text = "WIN" if player2.score > player1.score else "LOSE"
204 | hud_sprite.draw_text(hud_font, p1text, x - TEXT_OFFSET,
205 | TEXT_OFFSET, color=sge.gfx.Color("white"),
206 | halign="right", valign="top")
207 | hud_sprite.draw_text(hud_font, p2text, x + TEXT_OFFSET,
208 | TEXT_OFFSET, color=sge.gfx.Color("white"),
209 | halign="left", valign="top")
210 | game_in_progress = False
211 |
212 |
213 | def create_room():
214 | global player1
215 | global player2
216 | player1 = Player(1)
217 | player2 = Player(2)
218 | ball = Ball()
219 | return sge.dsp.Room([player1, player2, ball], background=background)
220 |
221 |
222 | def refresh_hud():
223 | # This fixes the HUD sprite so that it displays the correct score.
224 | hud_sprite.draw_clear()
225 | x = hud_sprite.width / 2
226 | hud_sprite.draw_text(hud_font, str(player1.score), x - TEXT_OFFSET,
227 | TEXT_OFFSET, color=sge.gfx.Color("white"),
228 | halign="right", valign="top")
229 | hud_sprite.draw_text(hud_font, str(player2.score), x + TEXT_OFFSET,
230 | TEXT_OFFSET, color=sge.gfx.Color("white"),
231 | halign="left", valign="top")
232 |
233 |
234 | # Create Game object
235 | Game(width=640, height=480, fps=120, window_text="Pong")
236 |
237 | # Load sprites
238 | paddle_sprite = sge.gfx.Sprite(width=8, height=48, origin_x=4, origin_y=24)
239 | ball_sprite = sge.gfx.Sprite(width=8, height=8, origin_x=4, origin_y=4)
240 | paddle_sprite.draw_rectangle(0, 0, paddle_sprite.width, paddle_sprite.height,
241 | fill=sge.gfx.Color("white"))
242 | ball_sprite.draw_rectangle(0, 0, ball_sprite.width, ball_sprite.height,
243 | fill=sge.gfx.Color("white"))
244 | hud_sprite = sge.gfx.Sprite(width=320, height=120, origin_x=160, origin_y=0)
245 |
246 | # Load backgrounds
247 | layers = [sge.gfx.BackgroundLayer(paddle_sprite, sge.game.width / 2, 0, -10000,
248 | repeat_up=True, repeat_down=True)]
249 | background = sge.gfx.Background(layers, sge.gfx.Color("black"))
250 |
251 | # Load fonts
252 | hud_font = sge.gfx.Font("Droid Sans Mono", size=48)
253 |
254 | # Load sounds
255 | bounce_sound = sge.snd.Sound(os.path.join(DATA, 'bounce.wav'))
256 | bounce_wall_sound = sge.snd.Sound(os.path.join(DATA, 'bounce_wall.wav'))
257 | score_sound = sge.snd.Sound(os.path.join(DATA, 'score.wav'))
258 |
259 | # Create rooms
260 | sge.game.start_room = create_room()
261 |
262 | sge.game.mouse.visible = False
263 | sge.game.fps_time = 0
264 | sge.game.fps_frames = 0
265 | sge.game.fps_text = ""
266 |
267 |
268 | if __name__ == '__main__':
269 | sge.game.start()
270 |
--------------------------------------------------------------------------------
/examples/rotation.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Rotation Example
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 |
23 |
24 | class Game(sge.dsp.Game):
25 | def event_key_press(self, key, char):
26 | if key == 'escape':
27 | self.end()
28 |
29 | def event_close(self):
30 | self.end()
31 |
32 |
33 | class Circle(sge.dsp.Object):
34 | def __init__(self, x, y):
35 | super(Circle, self).__init__(x, y, 5, sprite=rotator_sprite,
36 | regulate_origin=True,
37 | collision_precise=True)
38 |
39 | def event_create(self):
40 | self.image_alpha = 200
41 | if self.collision(sge.game.mouse):
42 | self.image_blend = sge.gfx.Color('#ff0000')
43 | else:
44 | self.image_blend = sge.gfx.Color('blue')
45 |
46 | if random.random() < 0.5:
47 | self.image_xscale = 2
48 | self.image_yscale = 2
49 |
50 | def event_step(self, time_passed, delta_mult):
51 | self.image_rotation += delta_mult
52 | sge.game.current_room.project_circle(self.x, self.y, self.z + 1, 8,
53 | outline=sge.gfx.Color("green"))
54 |
55 | if self.collision(sge.game.mouse):
56 | self.image_blend = sge.gfx.Color("red")
57 | else:
58 | self.image_blend = sge.gfx.Color((0, 0, 255))
59 |
60 |
61 | def main():
62 | global rotator_sprite
63 |
64 | # Create Game object
65 | game = Game(delta=True, collision_events_enabled=False)
66 |
67 | # Load sprites
68 | rotator_sprite = sge.gfx.Sprite('rotator', DATA)
69 | fence_sprite = sge.gfx.Sprite('fence', DATA)
70 |
71 | # Load backgrounds
72 | layers = [sge.gfx.BackgroundLayer(fence_sprite, 0, 380, 0,
73 | repeat_left=True, repeat_right=True)]
74 | background = sge.gfx.Background(layers, sge.gfx.Color(0xffffff))
75 |
76 | # Create objects
77 | circle = Circle(game.width // 2, game.height // 2)
78 | circle2 = Circle(22, 48)
79 | circle3 = Circle(486, 301)
80 | circle4 = Circle(50, 400)
81 | objects = (circle, circle2, circle3, circle4)
82 |
83 | # Create view
84 | views = [sge.dsp.View(0, 0)]
85 |
86 | # Create rooms
87 | game.start_room = sge.dsp.Room(objects, views=views, background=background)
88 |
89 | game.start()
90 |
91 |
92 | if __name__ == '__main__':
93 | main()
94 |
--------------------------------------------------------------------------------
/examples/splitscreen.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Splitscreen Example
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 |
23 | circles = []
24 |
25 |
26 | class Game(sge.dsp.Game):
27 |
28 | def event_step(self, time_passed, delta_mult):
29 | self.project_line(self.width / 2, 0, self.width / 2, self.height,
30 | sge.gfx.Color("black"), thickness=3)
31 | self.project_line(0, self.height / 2, self.width, self.height / 2,
32 | sge.gfx.Color("black"), thickness=3)
33 |
34 | def event_key_press(self, key, char):
35 | if key == 'escape':
36 | self.end()
37 | elif key in ("p", "enter"):
38 | self.pause()
39 |
40 | def event_close(self):
41 | self.end()
42 |
43 | def event_paused_key_press(self, key, char):
44 | self.unpause()
45 |
46 | def event_paused_close(self):
47 | self.event_close()
48 |
49 |
50 | class Circle(sge.dsp.Object):
51 | def __init__(self, x, y, player=0):
52 | super(Circle, self).__init__(x, y, 1, sprite=circle_sprite,
53 | collision_precise=True)
54 | self.player = player
55 | self.normal_image_blend = [sge.gfx.Color('red'), sge.gfx.Color('blue'),
56 | sge.gfx.Color('yellow'),
57 | sge.gfx.Color('green')][self.player]
58 | self.image_alpha = 128
59 |
60 | def set_color(self):
61 | if self.collision(Circle):
62 | self.image_blend = sge.gfx.Color('olive')
63 | else:
64 | self.image_blend = self.normal_image_blend
65 |
66 | def event_create(self):
67 | self.set_color()
68 |
69 | def event_step(self, time_passed, delta_mult):
70 | left_key = ['left', 'a', 'j', 'kp_4'][self.player]
71 | right_key = ['right', 'd', 'l', 'kp_6'][self.player]
72 | up_key = ['up', 'w', 'i', 'kp_8'][self.player]
73 | down_key = ['down', 's', 'k', 'kp_5'][self.player]
74 | self.xvelocity = (sge.keyboard.get_pressed(right_key) -
75 | sge.keyboard.get_pressed(left_key))
76 | self.yvelocity = (sge.keyboard.get_pressed(down_key) -
77 | sge.keyboard.get_pressed(up_key))
78 |
79 | # Limit the circles to inside the room.
80 | if self.bbox_left < 0:
81 | self.bbox_left = 0
82 | elif self.bbox_right >= sge.game.current_room.width:
83 | self.bbox_right = sge.game.current_room.width - 1
84 | if self.bbox_top < 0:
85 | self.bbox_top = 0
86 | elif self.bbox_bottom >= sge.game.current_room.height:
87 | self.bbox_bottom = sge.game.current_room.height - 1
88 |
89 | self.set_color()
90 |
91 | # Set view
92 | my_view = sge.game.current_room.views[self.player]
93 | my_view.x = self.x - (my_view.width // 2)
94 | my_view.y = self.y - (my_view.height // 2)
95 |
96 |
97 | def main():
98 | global circle_sprite
99 |
100 | # Create Game object
101 | Game(width=640, height=480, collision_events_enabled=False)
102 |
103 | # Load sprites
104 | circle_sprite = sge.gfx.Sprite('circle', DATA, width=32, height=32,
105 | origin_x=16, origin_y=16)
106 | fence = sge.gfx.Sprite('fence', DATA)
107 | sge.game.mouse_sprite = circle_sprite
108 |
109 | # Load backgrounds
110 | layers = [sge.gfx.BackgroundLayer(fence, 0, 0, 0, repeat_left=True,
111 | repeat_right=True, repeat_up=True,
112 | repeat_down=True)]
113 | background = sge.gfx.Background(layers, sge.gfx.Color('white'))
114 |
115 | # Create objects
116 | objects = []
117 | for i in range(4):
118 | circle = Circle(64, 64, i)
119 | objects.append(circle)
120 |
121 | # Create views
122 | views = []
123 | for x in range(2):
124 | for y in range(2):
125 | views.append(sge.dsp.View(0, 0, 320 * x, 240 * y, 320, 240))
126 |
127 | # Create rooms
128 | sge.game.start_room = sge.dsp.Room(objects, width=1280, height=1024,
129 | views=views, background=background)
130 |
131 | sge.game.start()
132 |
133 |
134 | if __name__ == '__main__':
135 | main()
136 |
137 |
--------------------------------------------------------------------------------
/examples/transitions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Transitions example
4 | #
5 | # To the extent possible under law, the author(s) have dedicated all
6 | # copyright and related and neighboring rights to this software to the
7 | # public domain worldwide. This software is distributed without any
8 | # warranty.
9 | #
10 | # You should have received a copy of the CC0 Public Domain Dedication
11 | # along with this software. If not, see
12 | # .
13 |
14 |
15 | import os
16 | import random
17 |
18 | import sge
19 |
20 |
21 | DATA = os.path.join(os.path.dirname(__file__), "data")
22 |
23 |
24 | class glob(object):
25 |
26 | font = None
27 | pop_sound = None
28 | music = None
29 | rooms = []
30 |
31 |
32 | class Game(sge.dsp.Game):
33 |
34 | def event_key_press(self, key, char):
35 | if key == 'escape':
36 | self.end()
37 |
38 | def event_close(self):
39 | self.end()
40 |
41 |
42 | class Circle(sge.dsp.Object):
43 |
44 | def __init__(self, x, y):
45 | super(Circle, self).__init__(x, y, 5, sprite=glob.circle_sprite,
46 | collision_precise=True)
47 |
48 | def event_create(self):
49 | self.image_alpha = 200
50 | if self.collision(sge.game.mouse):
51 | self.image_blend = sge.gfx.Color('#ff0000')
52 | else:
53 | self.image_blend = sge.gfx.Color('blue')
54 |
55 | def event_mouse_move(self, x, y):
56 | if self.collision(sge.game.mouse):
57 | self.image_blend = sge.gfx.Color("red")
58 | else:
59 | self.image_blend = sge.gfx.Color((0, 0, 255))
60 |
61 | def event_mouse_button_press(self, button):
62 | if button == 'left':
63 | if self.collision(sge.game.mouse):
64 | self.destroy()
65 |
66 | def event_destroy(self):
67 | pop = CirclePop(self.x, self.y)
68 | pop.image_blend = self.image_blend
69 | sge.game.current_room.add(pop)
70 | assert glob.pop_sound is not None
71 | glob.pop_sound.play()
72 |
73 |
74 | class CirclePop(sge.dsp.Object):
75 |
76 | def __init__(self, x, y):
77 | super(CirclePop, self).__init__(x, y, 5, sprite=glob.circle_pop_sprite,
78 | tangible=False)
79 |
80 | def event_animation_end(self):
81 | self.destroy()
82 |
83 | def event_destroy(self):
84 | circle = Circle(random.randint(0, sge.game.width),
85 | random.randint(0, sge.game.height))
86 | sge.game.current_room.add(circle)
87 |
88 |
89 | class Room(sge.dsp.Room):
90 |
91 | def __init__(self, text, objects=(), views=None, background=None):
92 | self.text = text
93 | super(Room, self).__init__(objects, views=views, background=background)
94 |
95 | def event_room_start(self):
96 | self.event_room_resume()
97 |
98 | def event_room_resume(self):
99 | sge.game.window_text = self.text
100 | glob.music.play(loops=None)
101 |
102 | def event_key_press(self, key, char):
103 | next_room = glob.rooms[(glob.rooms.index(self) + 1) % len(glob.rooms)]
104 | if key == "space":
105 | next_room.start()
106 | elif key == "1":
107 | next_room.start(transition="fade")
108 | elif key == "2":
109 | next_room.start(transition="dissolve")
110 | elif key == "3":
111 | next_room.start(transition="pixelate")
112 | elif key == "4":
113 | next_room.start(transition="wipe_left")
114 | elif key == "5":
115 | next_room.start(transition="wipe_right")
116 | elif key == "6":
117 | next_room.start(transition="wipe_up")
118 | elif key == "7":
119 | next_room.start(transition="wipe_down")
120 | elif key == "8":
121 | next_room.start(transition="wipe_upleft")
122 | elif key == "9":
123 | next_room.start(transition="wipe_upright")
124 | elif key == "0":
125 | next_room.start(transition="wipe_downleft")
126 | elif key == "q":
127 | next_room.start(transition="wipe_downright")
128 | elif key == "w":
129 | next_room.start(transition="wipe_matrix")
130 | elif key == "e":
131 | next_room.start(transition="iris_in")
132 | elif key == "r":
133 | next_room.start(transition="iris_out")
134 |
135 |
136 | def main():
137 | # Create Game object
138 | game = Game(collision_events_enabled=False)
139 |
140 | # Load sprites
141 | glob.circle_sprite = sge.gfx.Sprite('circle', DATA, width=64, height=64,
142 | origin_x=32, origin_y=32)
143 | glob.circle_pop_sprite = sge.gfx.Sprite('circle_pop', DATA, width=64,
144 | height=64, origin_x=32,
145 | origin_y=32, fps=60)
146 | fence_sprite = sge.gfx.Sprite('fence', DATA)
147 |
148 | # Load backgrounds
149 | layers = [sge.gfx.BackgroundLayer(fence_sprite, 0, 380, repeat_left=True,
150 | repeat_right=True)]
151 | layers2 = [sge.gfx.BackgroundLayer(fence_sprite, 0, 0, repeat_left=True,
152 | repeat_right=True, repeat_up=True,
153 | repeat_down=True)]
154 | background = sge.gfx.Background(layers, sge.gfx.Color(0xffffff))
155 | background2 = sge.gfx.Background(layers2, sge.gfx.Color('white'))
156 |
157 | # Load fonts
158 | glob.font = sge.gfx.Font('Liberation Serif', 20)
159 |
160 | # Load sounds
161 | glob.pop_sound = sge.snd.Sound(os.path.join(DATA, 'pop.ogg'))
162 |
163 | # Load music
164 | glob.music = sge.snd.Music(os.path.join(DATA, 'WhereWasI.ogg'))
165 |
166 | # Create objects
167 | circle = Circle(game.width // 2, game.height // 2)
168 | circle2 = Circle(22, 48)
169 | circle3 = Circle(486, 301)
170 | circle4 = Circle(50, 400)
171 | circle5 = Circle(game.width // 2, game.height // 2)
172 | circle6 = Circle(52, 120)
173 | objects = [circle, circle2, circle3, circle4]
174 | objects2 = [circle5, circle6]
175 |
176 | # Create view
177 | views = [sge.dsp.View(0, 0)]
178 |
179 | # Create rooms
180 | room1 = Room('I am the first room!', objects, views=views, background=background)
181 | room2 = Room('Second room on the house!', objects2, background=background2)
182 | room3 = Room('I am the third room!', objects, views=views, background=background)
183 | room4 = Room('Fourth room on the house!', objects2, background=background2)
184 | room5 = Room('I am the fifth room!', objects, views=views, background=background)
185 | room6 = Room('Sixth room on the house!', objects2, background=background2)
186 | glob.rooms = [room1, room2, room3, room4, room5, room6]
187 |
188 | game.start_room = room1
189 |
190 | game.start()
191 |
192 |
193 | if __name__ == '__main__':
194 | main()
195 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "sge"
3 | version = "2.0.2"
4 | description = "Seclusion Game Engine (Pygame implementation)"
5 | readme = {file = "README", content-type = "text/plain"}
6 | requires-python = ">=3.6"
7 | license = {file = "sge/COPYING.LESSER"}
8 | authors = [
9 | {name = "Diligent Circle", email = "diligentcircle@riseup.net"},
10 | ]
11 | classifiers = [
12 | "Development Status :: 5 - Production/Stable",
13 | "Intended Audience :: Developers",
14 | "License :: DFSG approved",
15 | "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
16 | "Natural Language :: English",
17 | "Operating System :: OS Independent",
18 | "Programming Language :: Python :: 3",
19 | "Topic :: Games/Entertainment",
20 | "Topic :: Software Development",
21 | ]
22 | dependencies = [
23 | "pygame (>=2.0.1)",
24 | "uniseg",
25 | ]
26 |
27 | [project.urls]
28 | homepage = "https://python-sge.github.io"
29 | documentation = "https://python-sge.github.io/doc/sge/index.html"
30 | repository = "https://github.com/python-sge/sge.git"
31 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # This file has been dedicated to the public domain, to the extent
2 | # possible under applicable law, via CC0. See
3 | # http://creativecommons.org/publicdomain/zero/1.0/ for more
4 | # information. This file is offered as-is, without any warranty.
5 |
6 | import sys
7 | from distutils.core import setup
8 |
9 | long_description = """
10 | The Seclusion Game Engine ("SGE") is a general-purpose 2-D game engine.
11 | It takes care of several details for you so you can focus on the game
12 | itself. This makes more rapid game development possible, and it also
13 | makes the SGE easy to learn.
14 |
15 | This implementation of the SGE uses Pygame as a backend.
16 | """.strip()
17 |
18 | setup(name="sge",
19 | version="2.0.3a0",
20 | description="Seclusion Game Engine (Pygame implementation)",
21 | long_description=long_description,
22 | author="Diligent Circle",
23 | author_email="diligentcircle@riseup.net",
24 | url="https://python-sge.github.io",
25 | classifiers=["Development Status :: 5 - Production/Stable",
26 | "Intended Audience :: Developers",
27 | "License :: DFSG approved",
28 | "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
29 | "Natural Language :: English",
30 | "Operating System :: OS Independent",
31 | "Programming Language :: Python :: 3",
32 | "Topic :: Games/Entertainment",
33 | "Topic :: Software Development"],
34 | license="GNU Lesser General Public License",
35 | packages=["sge"],
36 | package_dir={"sge": "sge"},
37 | package_data={"sge": ["COPYING", "COPYING.LESSER"]},
38 | requires=["pygame (>=2.0.1)", "uniseg"],
39 | provides=["sge"],
40 | )
41 |
--------------------------------------------------------------------------------
/sge/COPYING.LESSER:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/sge/__init__.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | The Seclusion Game Engine ("SGE") is a general-purpose 2-D game engine.
18 | It takes care of several details for you so you can focus on the game
19 | itself. This makes more rapid game development possible, and it also
20 | makes the SGE easy to learn.
21 |
22 | The SGE is libre open source software, and the SGE documentation
23 | (including all docstrings) is released to the public domain via CC0.
24 |
25 | Although it isn't required, please consider releasing your games' code
26 | under a libre software license, such as the GNU General Public License
27 | or the Apache License. Doing so is easy and typically does not
28 | negatively affect you. It's also just a real great thing to do.
29 |
30 | SGE Concepts
31 | ============
32 |
33 | Events
34 | ------
35 |
36 | The SGE uses an event-based system. When an event occurs, a certain
37 | event method (with a name that begins with ``event_``) is called. To
38 | define actions triggered by events, simply override the appropriate
39 | event method.
40 |
41 | At a lower level, it is possible to read "input events" from
42 | :attr:`sge.game.input_events` and handle them manually. See the
43 | documentation for :mod:`sge.input` for more information. This is not
44 | recommended, however, unless you are running your own loop for some
45 | reason (in which case it is necessary to do this in order to get input
46 | from the user).
47 |
48 | Position
49 | --------
50 |
51 | In all cases of positioning for the SGE, it is based on a
52 | two-dimensional graph with each unit being a pixel. This graph is not
53 | quite like regular graphs. The horizontal direction, normally called
54 | ``x``, is the same as the x-axis on a regular graph; ``0`` is the
55 | origin, positive numbers are to the right of the origin, and negative
56 | numbers are to the left of the origin. However, in the vertical
57 | direction, normally called ``y``, ``0`` is the origin, positive numbers
58 | are below the origin, and negative numbers are above the origin. While
59 | slightly jarring if you are used to normal graphs, this is in fact
60 | common in 2-D game development and is also how pixels in most image
61 | formats are indexed.
62 |
63 | Except where otherwise specified, the origin is always located at the
64 | top-leftmost position of an object.
65 |
66 | In addition to integers, position variables are allowed by the SGE to be
67 | floating-point numbers.
68 |
69 | Z-Axis
70 | ------
71 |
72 | The SGE uses a Z-axis to determine where objects are placed in the third
73 | dimension. Objects with a higher Z value are considered to be closer to
74 | the viewer and thus will be placed over objects which have a lower Z
75 | value. Note that the Z-axis does not allow 3-D gameplay or effects; it
76 | is only used to tell the SGE what to do with objects that overlap. For
77 | example, if an object called ``spam`` has a Z value of ``5`` while an
78 | object called ``eggs`` has a Z value of ``2``, ``spam`` will obscure
79 | part or all of ``eggs`` when the two objects overlap.
80 |
81 | If two objects with the same Z-axis value overlap, the object which was
82 | most recently added to the room is placed in front.
83 |
84 | The Game Loop
85 | -------------
86 |
87 | There can occasionally be times where you want to run your own loop,
88 | independent of the SGE's main loop. This is not recommended in general,
89 | but if you must (to freeze the game, for example), you should know the
90 | general game loop structure::
91 |
92 | while True:
93 | # Input events
94 | sge.game.pump_input()
95 | while sge.game.input_events:
96 | event = sge.game.input_events.pop(0)
97 |
98 | # Handle event
99 |
100 | # Regulate speed
101 | time_passed = sge.game.regulate_speed()
102 |
103 | # Logic (e.g. collision detection and step events)
104 |
105 | # Refresh
106 | sge.game.refresh()
107 |
108 | :meth:`sge.dsp.Game.pump_input` should be called frequently at all times
109 | regardless of whether or not user input is needed. This means it should
110 | be called every frame. It also means that should any task halt the loop
111 | for any noticeable period of time, arrangements should be made to call
112 | this method frequently during that time. Failing to call this method
113 | for a substantial period of time will cause the queue to build up, but
114 | more importantly, the OS may decide that the program has locked up if
115 | you wait for too long.
116 |
117 | :meth:`sge.dsp.Game.regulate_speed` limits the frame rate of the game
118 | and tells you how much time has passed since the last frame. It is not
119 | technically necessary, but using it is highly recommended; otherwise,
120 | the CPU will be working harder than it needs to and if things are
121 | moving, their speed will be irregular.
122 |
123 | :meth:`sge.dsp.Game.refresh` is necessary for any changes to the screen
124 | to be seen by the user. This includes new objects, removed objects, new
125 | projections, discontinued projections, etc.
126 |
127 | Global Variables and Constants
128 | ==============================
129 |
130 | .. data:: sge.IMPLEMENTATION
131 |
132 | A string indicating the name of the SGE implementation.
133 |
134 | .. data:: sge.SCALE_METHODS
135 |
136 | A list of specific scale methods supported by the SGE implementation.
137 |
138 | .. note::
139 |
140 | This list does not include the generic scale methods, ``"noblur"``
141 | and ``"smooth"``. It is also possible for this list to be empty.
142 |
143 | .. data:: sge.BLEND_NORMAL
144 |
145 | Flag indicating normal blending.
146 |
147 | .. data:: sge.BLEND_RGBA_ADD
148 |
149 | Flag indicating RGBA Addition blending: the red, green, blue, and
150 | alpha color values of the source are added to the respective color
151 | values of the destination, to a maximum of 255.
152 |
153 | .. data:: sge.BLEND_RGBA_SUBTRACT
154 |
155 | Flag indicating RGBA Subtract blending: the red, green, blue, and
156 | alpha color values of the source are subtracted from the respective
157 | color values of the destination, to a minimum of 0.
158 |
159 | .. data:: sge.BLEND_RGBA_MULTIPLY
160 |
161 | Flag indicating RGBA Multiply blending: the red, green, blue,
162 | and alpha color values of the source and destination are converted to
163 | values between 0 and 1 (divided by 255), the resulting destination
164 | color values are multiplied by the respective resulting source color
165 | values, and these results are converted back into values between 0
166 | and 255 (multiplied by 255).
167 |
168 | .. data:: sge.BLEND_RGBA_SCREEN
169 |
170 | Flag indicating RGBA Screen blending: the red, green, blue, and alpha
171 | color values of the source and destination are inverted (subtracted
172 | from 255) and converted to values between 0 and 1 (divided by 255),
173 | the resulting destination color values are multiplied by the
174 | respective resulting source color values, and these results are
175 | converted back into values between 0 and 255 (multiplied by 255) and
176 | inverted again (subtracted from 255).
177 |
178 | .. data:: sge.BLEND_RGBA_MINIMUM
179 |
180 | Flag indicating RGBA Minimum (Darken Only) blending: the smallest
181 | respective red, green, blue, and alpha color values out of the source
182 | and destination are used.
183 |
184 | .. data:: sge.BLEND_RGBA_MAXIMUM
185 |
186 | Flag indicating RGBA Maximum (Lighten Only) blending: the largest
187 | respective red, green, blue, and alpha color values out of the source
188 | and destination are used.
189 |
190 | .. data:: sge.BLEND_RGB_ADD
191 |
192 | Flag indicating RGB Addition blending: the same thing as RGBA
193 | Addition blending (see :data:`sge.BLEND_RGBA_ADD`) except the
194 | destination's alpha values are not changed.
195 |
196 | .. data:: sge.BLEND_RGB_SUBTRACT
197 |
198 | Flag indicating RGB Subtract blending: the same thing as RGBA
199 | Subtract blending (see :data:`sge.BLEND_RGBA_SUBTRACT`) except the
200 | destination's alpha values are not changed.
201 |
202 | .. data:: sge.BLEND_RGB_MULTIPLY
203 |
204 | Flag indicating RGB Multiply blending: the same thing as RGBA
205 | Multiply blending (see :data:`sge.BLEND_RGBA_MULTIPLY`) except the
206 | destination's alpha values are not changed.
207 |
208 | .. data:: sge.BLEND_RGB_SCREEN
209 |
210 | Flag indicating RGB Screen blending: the same thing as RGBA Screen
211 | blending (see :data:`sge.BLEND_RGBA_SCREEN`) except the destination's
212 | alpha values are not changed.
213 |
214 | .. data:: sge.BLEND_RGB_MINIMUM
215 |
216 | Flag indicating RGB Minimum (Darken Only) blending: the same thing
217 | as RGBA Minimum blending (see :data:`sge.BLEND_RGBA_MINIMUM`) except
218 | the destination's alpha values are not changed.
219 |
220 | .. data:: sge.BLEND_RGB_MAXIMUM
221 |
222 | Flag indicating RGB Maximum (Lighten Only) blending: the same thing
223 | as RGBA Maximum blending (see :data:`sge.BLEND_RGBA_MAXIMUM`) except
224 | the destination's alpha values are not changed.
225 |
226 | .. data:: sge.game
227 |
228 | Stores the current :class:`sge.dsp.Game` object. If there is no
229 | :class:`sge.dsp.Game` object currently, this variable is set to
230 | ``None``.
231 | """
232 |
233 |
234 | __version__ = "2.0.3a0"
235 | __all__ = [
236 | # Modules
237 | "collision",
238 | "gfx",
239 | "input",
240 | "joystick",
241 | "keyboard",
242 | "mouse",
243 |
244 | # Constants
245 | 'IMPLEMENTATION',
246 | 'BLEND_RGBA_ADD',
247 | 'BLEND_RGBA_SUBTRACT',
248 | 'BLEND_RGBA_MULTIPLY',
249 | 'BLEND_RGBA_SCREEN',
250 | 'BLEND_RGBA_MINIMUM',
251 | 'BLEND_RGBA_MAXIMUM',
252 | 'BLEND_RGB_ADD',
253 | 'BLEND_RGB_SUBTRACT',
254 | 'BLEND_RGB_MULTIPLY',
255 | 'BLEND_RGB_SCREEN',
256 | 'BLEND_RGB_MINIMUM',
257 | 'BLEND_RGB_MAXIMUM',
258 | ]
259 |
260 |
261 | import sys
262 | import os
263 |
264 | import pygame
265 |
266 |
267 | # Constants
268 | IMPLEMENTATION = "Pygame SGE"
269 | SCALE_METHODS = ["scale2x"]
270 |
271 | BLEND_NORMAL = None
272 | BLEND_ALPHA = 1
273 | BLEND_RGB_ADD = 2
274 | BLEND_RGB_SUBTRACT = 4
275 | BLEND_RGB_MULTIPLY = 6
276 | BLEND_RGB_SCREEN = 8
277 | BLEND_RGB_MINIMUM = 10
278 | BLEND_RGB_MAXIMUM = 12
279 |
280 | BLEND_RGBA_ADD = BLEND_ALPHA | BLEND_RGB_ADD
281 | BLEND_RGBA_SUBTRACT = BLEND_ALPHA | BLEND_RGB_SUBTRACT
282 | BLEND_RGBA_MULTIPLY = BLEND_ALPHA | BLEND_RGB_MULTIPLY
283 | BLEND_RGBA_SCREEN = BLEND_ALPHA | BLEND_RGB_SCREEN
284 | BLEND_RGBA_MINIMUM = BLEND_ALPHA | BLEND_RGB_MINIMUM
285 | BLEND_RGBA_MAXIMUM = BLEND_ALPHA | BLEND_RGB_MAXIMUM
286 |
287 | MUSIC_END_EVENT = pygame.USEREVENT + 1
288 | MUSIC_END_BLOCK_EVENT = pygame.USEREVENT + 2
289 |
290 | KEYS = {"0": pygame.K_0, "1": pygame.K_1, "2": pygame.K_2, "3": pygame.K_3,
291 | "4": pygame.K_4, "5": pygame.K_5, "6": pygame.K_6, "7": pygame.K_7,
292 | "8": pygame.K_8, "9": pygame.K_9, "a": pygame.K_a, "b": pygame.K_b,
293 | "c": pygame.K_c, "d": pygame.K_d, "e": pygame.K_e, "f": pygame.K_f,
294 | "g": pygame.K_g, "h": pygame.K_h, "i": pygame.K_i, "j": pygame.K_j,
295 | "k": pygame.K_k, "l": pygame.K_l, "m": pygame.K_m, "n": pygame.K_n,
296 | "o": pygame.K_o, "p": pygame.K_p, "q": pygame.K_q, "r": pygame.K_r,
297 | "s": pygame.K_s, "t": pygame.K_t, "u": pygame.K_u, "v": pygame.K_v,
298 | "w": pygame.K_w, "x": pygame.K_x, "y": pygame.K_y, "z": pygame.K_z,
299 | "alt_left": pygame.K_LALT, "alt_right": pygame.K_RALT,
300 | "ampersand": pygame.K_AMPERSAND, "apostrophe": pygame.K_QUOTE,
301 | "asterisk": pygame.K_ASTERISK, "at": pygame.K_AT,
302 | "backslash": pygame.K_BACKSLASH, "backspace": pygame.K_BACKSPACE,
303 | "backtick": pygame.K_BACKQUOTE, "bracket_left": pygame.K_LEFTBRACKET,
304 | "bracket_right": pygame.K_RIGHTBRACKET, "break": pygame.K_BREAK,
305 | "caps_lock": pygame.K_CAPSLOCK, "caret": pygame.K_CARET,
306 | "undef_clear": pygame.K_CLEAR, "colon": pygame.K_COLON,
307 | "comma": pygame.K_COMMA, "ctrl_left": pygame.K_LCTRL,
308 | "ctrl_right": pygame.K_RCTRL, "delete": pygame.K_DELETE,
309 | "dollar": pygame.K_DOLLAR, "down": pygame.K_DOWN, "end": pygame.K_END,
310 | "enter": pygame.K_RETURN, "equals": pygame.K_EQUALS,
311 | "escape": pygame.K_ESCAPE, "euro": pygame.K_EURO,
312 | "exclamation": pygame.K_EXCLAIM, "f1": pygame.K_F1, "f2": pygame.K_F2,
313 | "f3": pygame.K_F3, "f4": pygame.K_F4, "f5": pygame.K_F5,
314 | "f6": pygame.K_F6, "f7": pygame.K_F7, "f8": pygame.K_F8,
315 | "f9": pygame.K_F9, "f10": pygame.K_F10, "f11": pygame.K_F11,
316 | "f12": pygame.K_F12, "greater_than": pygame.K_GREATER,
317 | "hash": pygame.K_HASH, "undef_help": pygame.K_HELP,
318 | "home": pygame.K_HOME, "hyphen": pygame.K_MINUS,
319 | "insert": pygame.K_INSERT,
320 | "kp_0": pygame.K_KP0, "kp_1": pygame.K_KP1, "kp_2": pygame.K_KP2,
321 | "kp_3": pygame.K_KP3, "kp_4": pygame.K_KP4, "kp_5": pygame.K_KP5,
322 | "kp_6": pygame.K_KP6, "kp_7": pygame.K_KP7, "kp_8": pygame.K_KP8,
323 | "kp_9": pygame.K_KP9, "kp_divide": pygame.K_KP_DIVIDE,
324 | "kp_enter": pygame.K_KP_ENTER, "kp_equals": pygame.K_KP_EQUALS,
325 | "kp_minus": pygame.K_KP_MINUS, "kp_multiply": pygame.K_KP_MULTIPLY,
326 | "kp_plus": pygame.K_KP_PLUS, "kp_point": pygame.K_KP_PERIOD,
327 | "left": pygame.K_LEFT, "less_than": pygame.K_LESS,
328 | "menu": pygame.K_MENU, "meta_left": pygame.K_LMETA,
329 | "meta_right": pygame.K_RMETA, "undef_mode": pygame.K_MODE,
330 | "num_lock": pygame.K_NUMLOCK, "pagedown": pygame.K_PAGEDOWN,
331 | "pageup": pygame.K_PAGEUP, "parenthesis_left": pygame.K_LEFTPAREN,
332 | "parenthesis_right": pygame.K_RIGHTPAREN, "pause": pygame.K_PAUSE,
333 | "period": pygame.K_PERIOD, "plus": pygame.K_PLUS,
334 | "undef_power": pygame.K_POWER, "print_screen": pygame.K_PRINT,
335 | "question": pygame.K_QUESTION, "quote": pygame.K_QUOTEDBL,
336 | "right": pygame.K_RIGHT, "scroll_lock": pygame.K_SCROLLOCK,
337 | "semicolon": pygame.K_SEMICOLON, "shift_left": pygame.K_LSHIFT,
338 | "shift_right": pygame.K_RSHIFT, "slash": pygame.K_SLASH,
339 | "space": pygame.K_SPACE, "undef_super_left": pygame.K_LSUPER,
340 | "undef_super_right": pygame.K_RSUPER, "sysrq": pygame.K_SYSREQ,
341 | "tab": pygame.K_TAB, "underscore": pygame.K_UNDERSCORE,
342 | "up": pygame.K_UP}
343 | KEY_NAMES = {}
344 | for pair in KEYS.items():
345 | KEY_NAMES[pair[1]] = pair[0]
346 |
347 | MODS = {"alt": pygame.KMOD_ALT, "alt_left": pygame.KMOD_LALT,
348 | "alt_right": pygame.KMOD_RALT, "caps_lock": pygame.KMOD_CAPS,
349 | "ctrl": pygame.KMOD_CTRL, "ctrl_left": pygame.KMOD_LCTRL,
350 | "ctrl_right": pygame.KMOD_RCTRL, "meta": pygame.KMOD_META,
351 | "meta_left": pygame.KMOD_LMETA, "meta_right": pygame.KMOD_RMETA,
352 | "mode": pygame.KMOD_MODE, "num_lock": pygame.KMOD_NUM,
353 | "shift": pygame.KMOD_SHIFT, "shift_left": pygame.KMOD_LSHIFT,
354 | "shift_right": pygame.KMOD_RSHIFT}
355 |
356 | MOUSE_BUTTONS = {"left": 1, "right": 3, "middle": 2, "wheel_up": 4,
357 | "wheel_down": 5, "extra1": 6, "extra2": 7}
358 | MOUSE_BUTTON_NAMES = {}
359 | for pair in MOUSE_BUTTONS.items():
360 | MOUSE_BUTTON_NAMES[pair[1]] = pair[0]
361 |
362 |
363 | from sge import (collision, dsp, gfx, input, joystick, keyboard, mouse, snd, s,
364 | r)
365 |
366 |
367 | # Global variables
368 | game = None
369 |
370 | os.environ['PYGAME_FREETYPE'] = '1'
371 |
372 | # Uncomment this line to tell SDL to center the window. Disabled by
373 | # default because it seems to cause some weird behavior with window
374 | # resizing on at least some systems.
375 | #os.environ['SDL_VIDEO_CENTERED'] = '1'
376 |
--------------------------------------------------------------------------------
/sge/collision.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides easy-to-use collision detection functions, from
18 | basic rectangle-based collision detection to shape-based collision
19 | detection.
20 | """
21 |
22 |
23 | import math
24 |
25 | import sge
26 | from sge import r
27 | from sge.r import s_get_precise_mask
28 |
29 |
30 | __all__ = ["rectangles_collide", "masks_collide", "rectangle", "ellipse",
31 | "circle", "line"]
32 |
33 |
34 | def rectangles_collide(x1, y1, w1, h1, x2, y2, w2, h2):
35 | """
36 | Return whether or not two rectangles collide.
37 |
38 | Parameters:
39 |
40 | - ``x1`` -- The horizontal position of the first rectangle.
41 | - ``y1`` -- The vertical position of the first rectangle.
42 | - ``w1`` -- The width of the first rectangle.
43 | - ``h1`` -- The height of the first rectangle.
44 | - ``x2`` -- The horizontal position of the second rectangle.
45 | - ``y2`` -- The vertical position of the second rectangle.
46 | - ``w2`` -- The width of the second rectangle.
47 | - ``h2`` -- The height of the second rectangle.
48 | """
49 | return (x1 < x2 + w2 and x1 + w1 > x2 and y1 < y2 + h2 and y1 + h1 > y2)
50 |
51 |
52 | def masks_collide(x1, y1, mask1, x2, y2, mask2):
53 | """
54 | Return whether or not two masks collide.
55 |
56 | Parameters:
57 |
58 | - ``x1`` -- The horizontal position of the first mask.
59 | - ``y1`` -- The vertical position of the first mask.
60 | - ``mask1`` -- The first mask (see below).
61 | - ``x2`` -- The horizontal position of the second mask.
62 | - ``y2`` -- The vertical position of the second mask.
63 | - ``mask2`` -- The second mask (see below).
64 |
65 | ``mask1`` and ``mask2`` are both lists of lists of boolean values.
66 | Each value in the mask indicates whether or not a pixel is counted
67 | as a collision; the masks collide if at least one pixel at the same
68 | location is :const:`True` for both masks.
69 |
70 | Masks are indexed as ``mask[x][y]``, where ``x`` is the column and
71 | ``y`` is the row.
72 | """
73 | if mask1 and mask2 and mask1[0] and mask2[0]:
74 | x1 = round(x1)
75 | y1 = round(y1)
76 | w1 = len(mask1)
77 | h1 = len(mask1[0])
78 | x2 = round(x2)
79 | y2 = round(y2)
80 | w2 = len(mask2)
81 | h2 = len(mask2[0])
82 |
83 | if rectangles_collide(x1, y1, w1, h1, x2, y2, w2, h2):
84 | for i in range(max(x1, x2), min(x1 + w1, x2 + w2)):
85 | for j in range(max(y1, y2), min(y1 + h1, y2 + h2)):
86 | if (mask1[i - x1][j - y1] and mask2[i - x2][j - y2]):
87 | return True
88 |
89 | return False
90 |
91 |
92 | def rectangle(x, y, w, h, other=None):
93 | """
94 | Return a list of objects colliding with a rectangle.
95 |
96 | Parameters:
97 |
98 | - ``x`` -- The horizontal position of the rectangle.
99 | - ``y`` -- The vertical position of the rectangle.
100 | - ``w`` -- The width of the rectangle.
101 | - ``h`` -- The height of the rectangle.
102 | - ``other`` -- What to check for collisions with. See the
103 | documentation for :meth:`sge.dsp.Object.collision` for more
104 | information.
105 | """
106 | room = sge.game.current_room
107 | others = room.get_objects_at(x, y, w, h)
108 | collisions = []
109 | mask_id = ("rectangle_masks", x, y, w, h)
110 |
111 | mask = r.cache.get(mask_id)
112 | if mask is None:
113 | mask = [[True for j in range(int(h))] for i in range(int(w))]
114 |
115 | r.cache.add(mask_id, mask)
116 |
117 | for obj in others:
118 | if obj.tangible and r.o_is_other(obj, other):
119 | if obj.collision_precise or obj.collision_ellipse:
120 | if masks_collide(x, y, mask, obj.mask_x, obj.mask_y, obj.mask):
121 | collisions.append(obj)
122 | else:
123 | if rectangles_collide(x, y, w, h, obj.bbox_left, obj.bbox_top,
124 | obj.bbox_width, obj.bbox_height):
125 | collisions.append(obj)
126 |
127 | return collisions
128 |
129 |
130 | def ellipse(x, y, w, h, other=None):
131 | """
132 | Return a list of objects colliding with an ellipse.
133 |
134 | Parameters:
135 |
136 | - ``x`` -- The horizontal position of the imaginary rectangle
137 | containing the ellipse.
138 | - ``y`` -- The vertical position of the imaginary rectangle
139 | containing the ellipse.
140 | - ``w`` -- The width of the ellipse.
141 | - ``h`` -- The height of the ellipse.
142 | - ``other`` -- What to check for collisions with. See the
143 | documentation for :meth:`sge.dsp.Object.collision` for more
144 | information.
145 | """
146 | room = sge.game.current_room
147 | others = room.get_objects_at(x, y, w, h)
148 | collisions = []
149 | mask_id = ("ellipse_masks", x, y, w, h)
150 |
151 | mask = r.cache.get(mask_id)
152 |
153 | if mask is None:
154 | mask = [[False for j in range(int(h))] for i in range(int(w))]
155 | a = len(mask) / 2
156 | b = len(mask[0]) / 2 if mask else 0
157 |
158 | for i, column in enumerate(mask):
159 | for j, row in enumerate(column):
160 | if ((i - a) / a) ** 2 + ((j - b) / b) ** 2 <= 1:
161 | mask[i][j] = True
162 |
163 | r.cache.add(mask_id, mask)
164 |
165 | for obj in others:
166 | if (obj.tangible and r.o_is_other(obj, other) and
167 | masks_collide(x, y, mask, obj.mask_x, obj.mask_y, obj.mask)):
168 | collisions.append(obj)
169 |
170 | return collisions
171 |
172 |
173 | def circle(x, y, radius, other=None):
174 | """
175 | Return a list of objects colliding with a circle.
176 |
177 | Parameters:
178 |
179 | - ``x`` -- The horizontal position of the center of the circle.
180 | - ``y`` -- The vertical position of the center of the circle.
181 | - ``radius`` -- The radius of the circle.
182 | - ``other`` -- What to check for collisions with. See the
183 | documentation for :meth:`sge.dsp.Object.collision` for more
184 | information.
185 | """
186 | room = sge.game.current_room
187 | diameter = radius * 2
188 | others = room.get_objects_at(x - radius, y - radius, diameter, diameter)
189 | collisions = []
190 | mask_id = ("circle_masks", x, y, radius)
191 |
192 | mask = r.cache.get(mask_id)
193 |
194 | if mask is None:
195 | mask = [[False for j in range(int(diameter))]
196 | for i in range(int(diameter))]
197 |
198 | for i, column in enumerate(mask):
199 | for j, row in enumerate(column):
200 | if (i - x) ** 2 + (j - y) ** 2 <= radius ** 2:
201 | mask[i][j] = True
202 |
203 | r.cache.add(mask_id, mask)
204 |
205 | for obj in others:
206 | if (obj.tangible and r.o_is_other(obj, other) and
207 | masks_collide(x - radius, y - radius, mask, obj.mask_x,
208 | obj.mask_y, obj.mask)):
209 | collisions.append(obj)
210 |
211 | return collisions
212 |
213 |
214 | def line(x1, y1, x2, y2, other=None):
215 | """
216 | Return a list of objects colliding with a line segment.
217 |
218 | Parameters:
219 |
220 | - ``x1`` -- The horizontal position of the first endpoint of the
221 | line segment.
222 | - ``y1`` -- The vertical position of the first endpoint of the line
223 | segment.
224 | - ``x2`` -- The horizontal position of the second endpoint of the
225 | line segment.
226 | - ``y2`` -- The vertical position of the second endpoint of the line
227 | segment.
228 | - ``other`` -- What to check for collisions with. See the
229 | documentation for :meth:`sge.dsp.Object.collision` for more
230 | information.
231 | """
232 | room = sge.game.current_room
233 | x = min(x1, x2)
234 | y = min(y1, y2)
235 | w = abs(x2 - x1) + 1
236 | h = abs(y2 - y1) + 1
237 |
238 | if w <= 1 or h <= 1:
239 | return rectangle(x, y, w, h)
240 |
241 | others = room.get_objects_at(x, y, w, h)
242 | collisions = []
243 | mask_id = ("line_masks", x1 - x, y1 - y, x2 - x, y2 - y, w, h)
244 |
245 | mask = r.cache.get(mask_id)
246 |
247 | if mask is None:
248 | sp = sge.gfx.Sprite(width=w, height=h)
249 | sp.draw_line(x1 - x, y1 - y, x2 - x, y2 - y, sge.gfx.Color("white"))
250 | mask = s_get_precise_mask(sp, 0, 1, 1, 0)
251 |
252 | r.cache.add(mask_id, mask)
253 |
254 | for obj in others:
255 | if (obj.tangible and r.o_is_other(obj, other) and
256 | masks_collide(x, y, mask, obj.mask_x, obj.mask_y, obj.mask)):
257 | collisions.append(obj)
258 |
259 | return collisions
260 |
--------------------------------------------------------------------------------
/sge/input.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides input event classes. Input event objects are used
18 | to consolidate all necessary information about input events in a clean
19 | way.
20 |
21 | You normally don't need to use input event objects directly. Input
22 | events are handled automatically in each frame of the SGE's main loop.
23 | You only need to use input event objects directly if you take control
24 | away from the SGE's main loop, e.g. to create your own loop.
25 | """
26 |
27 |
28 | __all__ = ["KeyPress", "KeyRelease", "MouseMove", "MouseButtonPress",
29 | "MouseButtonRelease", "JoystickAxisMove", "JoystickHatMove",
30 | "JoystickTrackballMove", "JoystickButtonPress",
31 | "JoystickButtonRelease", "JoystickEvent", "KeyboardFocusGain",
32 | "KeyboardFocusLose", "MouseFocusGain", "MouseFocusLose",
33 | "QuitRequest"]
34 |
35 |
36 | class KeyPress:
37 |
38 | """
39 | This input event represents a key on the keyboard being pressed.
40 |
41 | .. attribute:: key
42 |
43 | The identifier string of the key that was pressed. See the
44 | table in the documentation for :mod:`sge.keyboard`.
45 |
46 | .. attribute:: char
47 |
48 | The unicode string associated with the key press, or an empty
49 | unicode string if no text is associated with the key press.
50 | See the table in the documentation for :mod:`sge.keyboard`.
51 | """
52 |
53 | def __init__(self, key, char):
54 | self.key = key
55 | self.char = char
56 |
57 |
58 | class KeyRelease:
59 |
60 | """
61 | This input event represents a key on the keyboard being released.
62 |
63 | .. attribute:: key
64 |
65 | The identifier string of the key that was released. See the
66 | table in the documentation for :class:`sge.input.KeyPress`.
67 | """
68 |
69 | def __init__(self, key):
70 | self.key = key
71 |
72 |
73 | class MouseMove:
74 |
75 | """
76 | This input event represents the mouse being moved.
77 |
78 | .. attribute:: x
79 |
80 | The horizontal relative movement of the mouse.
81 |
82 | .. attribute:: y
83 |
84 | The vertical relative movement of the mouse.
85 | """
86 |
87 | def __init__(self, x, y):
88 | self.x = x
89 | self.y = y
90 |
91 |
92 | class MouseButtonPress:
93 |
94 | """
95 | This input event represents a mouse button being pressed.
96 |
97 | .. attribute:: button
98 |
99 | The identifier string of the mouse button that was pressed. See
100 | the table below.
101 |
102 | ====================== =================
103 | Mouse Button Name Identifier String
104 | ====================== =================
105 | Left mouse button ``"left"``
106 | Right mouse button ``"right"``
107 | Middle mouse button ``"middle"``
108 | Extra mouse button 1 ``"extra1"``
109 | Extra mouse button 2 ``"extra2"``
110 | ====================== =================
111 | """
112 |
113 | def __init__(self, button):
114 | self.button = button
115 |
116 |
117 | class MouseButtonRelease:
118 |
119 | """
120 | This input event represents a mouse button being released.
121 |
122 | .. attribute:: button
123 |
124 | The identifier string of the mouse button that was released. See
125 | the table in the documentation for
126 | :class:`sge.input.MouseButtonPress`.
127 | """
128 |
129 | def __init__(self, button):
130 | self.button = button
131 |
132 |
133 | class MouseWheelMove:
134 |
135 | """
136 | This input event represents a mouse wheel moving.
137 |
138 | .. attribute:: x
139 |
140 | The horizontal scroll amount, where ``-1`` is to the left, ``1``
141 | is to the right, and ``0`` is no horizontal scrolling.
142 |
143 | .. attribute:: y
144 |
145 | The vertical scroll amount, where ``-1`` is up, ``1`` is down,
146 | and ``0`` is no vertical scrolling.
147 | """
148 |
149 | def __init__(self, x, y):
150 | self.x = x
151 | self.y = y
152 |
153 |
154 | class JoystickAxisMove:
155 |
156 | """
157 | This input event represents a joystick axis moving.
158 |
159 | .. attribute:: js_name
160 |
161 | The name of the joystick.
162 |
163 | .. attribute:: js_id
164 |
165 | The number of the joystick, where ``0`` is the first joystick.
166 |
167 | .. attribute:: axis
168 |
169 | The number of the axis that moved, where ``0`` is the first axis
170 | on the joystick.
171 |
172 | .. attribute:: value
173 |
174 | The tilt of the axis as a float from ``-1`` to ``1``, where ``0``
175 | is centered, ``-1`` is all the way to the left or up, and ``1``
176 | is all the way to the right or down.
177 | """
178 |
179 | def __init__(self, js_name, js_id, axis, value):
180 | self.js_name = js_name
181 | self.js_id = js_id
182 | self.axis = axis
183 | self.value = max(-1.0, min(value, 1.0))
184 |
185 |
186 | class JoystickHatMove:
187 |
188 | """
189 | This input event represents a joystick hat moving.
190 |
191 | .. attribute:: js_name
192 |
193 | The name of the joystick.
194 |
195 | .. attribute:: js_id
196 |
197 | The number of the joystick, where ``0`` is the first joystick.
198 |
199 | .. attribute:: hat
200 |
201 | The number of the hat that moved, where ``0`` is the first axis
202 | on the joystick.
203 |
204 | .. attribute:: x
205 |
206 | The horizontal position of the hat, where ``0`` is centered,
207 | ``-1`` is left, and ``1`` is right.
208 |
209 | .. attribute:: y
210 |
211 | The vertical position of the hat, where ``0`` is centered, ``-1``
212 | is up, and ``1`` is down.
213 | """
214 |
215 | def __init__(self, js_name, js_id, hat, x, y):
216 | self.js_name = js_name
217 | self.js_id = js_id
218 | self.hat = hat
219 | self.x = x
220 | self.y = y
221 |
222 |
223 | class JoystickTrackballMove:
224 |
225 | """
226 | This input event represents a joystick trackball moving.
227 |
228 | .. attribute:: js_name
229 |
230 | The name of the joystick.
231 |
232 | .. attribute:: js_id
233 |
234 | The number of the joystick, where ``0`` is the first joystick.
235 |
236 | .. attribute:: ball
237 |
238 | The number of the trackball that moved, where ``0`` is the first
239 | trackball on the joystick.
240 |
241 | .. attribute:: x
242 |
243 | The horizontal relative movement of the trackball.
244 |
245 | .. attribute:: y
246 |
247 | The vertical relative movement of the trackball.
248 | """
249 |
250 | def __init__(self, js_name, js_id, ball, x, y):
251 | self.js_name = js_name
252 | self.js_id = js_id
253 | self.ball = ball
254 | self.x = x
255 | self.y = y
256 |
257 |
258 | class JoystickButtonPress:
259 |
260 | """
261 | This input event represents a joystick button being pressed.
262 |
263 | .. attribute:: js_name
264 |
265 | The name of the joystick.
266 |
267 | .. attribute:: js_id
268 |
269 | The number of the joystick, where ``0`` is the first joystick.
270 |
271 | .. attribute:: button
272 |
273 | The number of the button that was pressed, where ``0`` is the
274 | first button on the joystick.
275 | """
276 |
277 | def __init__(self, js_name, js_id, button):
278 | self.js_name = js_name
279 | self.js_id = js_id
280 | self.button = button
281 |
282 |
283 | class JoystickButtonRelease:
284 |
285 | """
286 | This input event represents a joystick button being released.
287 |
288 | .. attribute:: js_name
289 |
290 | The name of the joystick.
291 |
292 | .. attribute:: js_id
293 |
294 | The number of the joystick, where ``0`` is the first joystick.
295 |
296 | .. attribute:: button
297 |
298 | The number of the button that was released, where ``0`` is the
299 | first button on the joystick.
300 | """
301 |
302 | def __init__(self, js_name, js_id, button):
303 | self.js_name = js_name
304 | self.js_id = js_id
305 | self.button = button
306 |
307 |
308 | class JoystickEvent:
309 |
310 | """
311 | This input event represents the movement of any joystick input.
312 | This makes it possible to treat all joystick inputs the same way,
313 | which can be used to simplify things like control customization.
314 |
315 | .. attribute:: js_name
316 |
317 | The name of the joystick.
318 |
319 | .. attribute:: js_id
320 |
321 | The number of the joystick, where ``0`` is the first joystick.
322 |
323 | .. attribute:: input_type
324 |
325 | The type of joystick control that was moved. Can be one of the
326 | following:
327 |
328 | - ``"axis-"`` -- The tilt of a joystick axis to the left or up
329 | changes.
330 | - ``"axis+"`` -- The tilt of a joystick axis to the right or down
331 | changes.
332 | - ``"axis0"`` -- The tilt of a joystick axis changes.
333 | - ``"hat_left"`` -- Whether or not a joystick hat's position is
334 | to the left changes.
335 | - ``"hat_right"`` -- Whether or not a joystick hat's position is
336 | to the right changes.
337 | - ``"hat_center_x"`` -- Whether or not a joystick hat is
338 | horizontally centered changes.
339 | - ``"hat_up"`` -- Whether or not a joystick hat's position is up
340 | changes.
341 | - ``"hat_down"`` -- Whether or not a joystick hat's position is
342 | down changes.
343 | - ``"hat_center_y"`` -- Whether or not a joystick hat is
344 | vertically centered changes.
345 | - ``"trackball_left"`` -- A joystick trackball is moved left.
346 | - ``"trackball_right"`` -- A joystick trackball is moved right.
347 | - ``"trackball_up"`` -- A joystick trackball is moved up.
348 | - ``"trackball_down"`` -- A joystick trackball is moved down.
349 | - ``"button"`` -- Whether or not a joystick button is pressed
350 | changes.
351 |
352 | .. attribute:: input_id
353 |
354 | The number of the joystick control that was moved, where ``0`` is
355 | the first control of its type on the joystick.
356 |
357 | .. attribute:: value
358 |
359 | The value of the event, which is different depending on the value
360 | of :attr:`input_type`. If :attr:`input_type` is
361 | ``"trackball_left"``, ``"trackball_right"``, ``"trackball_up"``,
362 | or ``"trackball_down"``, this is the relative movement of the
363 | trackball in the respective direction. Otherwise, this is the
364 | new value of the respective control. See the documentation for
365 | :func:`sge.joystick.get_value` for more information.
366 | """
367 |
368 | def __init__(self, js_name, js_id, input_type, input_id, value):
369 | self.js_name = js_name
370 | self.js_id = js_id
371 | self.input_type = input_type
372 | self.input_id = input_id
373 | self.value = value
374 |
375 |
376 | class KeyboardFocusGain:
377 |
378 | """
379 | This input event represents the game window gaining keyboard focus.
380 | Keyboard focus is normally needed for keyboard input to be received.
381 |
382 | .. note::
383 |
384 | On some window systems, such as the one used by Windows, no
385 | distinction is made between keyboard and mouse focus, but on
386 | some other window systems, such as the X Window System, a
387 | distinction is made: one window can have keyboard focus while
388 | another has mouse focus. Be careful to observe the
389 | difference; failing to do so may result in annoying bugs,
390 | and you won't notice these bugs if you are testing on a
391 | window manager that doesn't recognize the difference.
392 | """
393 |
394 |
395 | class KeyboardFocusLose:
396 |
397 | """
398 | This input event represents the game window losing keyboard focus.
399 | Keyboard focus is normally needed for keyboard input to be received.
400 |
401 | .. note::
402 |
403 | See the note in the documentation for
404 | :class:`sge.input.KeyboardFocusGain`.
405 | """
406 |
407 |
408 | class MouseFocusGain:
409 |
410 | """
411 | This input event represents the game window gaining mouse focus.
412 | Mouse focus is normally needed for mouse input to be received.
413 |
414 | .. note::
415 |
416 | See the note in the documentation for
417 | :class:`sge.input.KeyboardFocusGain`.
418 | """
419 |
420 |
421 | class MouseFocusLose:
422 |
423 | """
424 | This input event represents the game window losing mouse focus.
425 | Mouse focus is normally needed for mouse input to be received.
426 |
427 | .. note::
428 |
429 | See the note in the documentation for
430 | :class:`sge.input.KeyboardFocusGain`.
431 | """
432 |
433 |
434 | class WindowResize:
435 |
436 | """
437 | This input event represents the player resizing the window.
438 | """
439 |
440 |
441 | class QuitRequest:
442 |
443 | """
444 | This input event represents the OS requesting for the program to
445 | close (e.g. when the user presses a "close" button on the window
446 | border).
447 | """
448 |
--------------------------------------------------------------------------------
/sge/joystick.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides functions related to joystick input.
18 | """
19 |
20 |
21 | __all__ = ["refresh", "get_axis", "get_hat_x", "get_hat_y",
22 | "get_pressed", "get_value", "get_joysticks", "get_name",
23 | "get_id", "get_axes", "get_hats", "get_trackballs", "get_buttons"]
24 |
25 |
26 | import pygame
27 |
28 | import sge
29 | from sge import r
30 |
31 |
32 | def refresh():
33 | """
34 | Refresh the SGE's knowledge of joysticks.
35 |
36 | Call this method to allow the SGE to use joysticks that were plugged
37 | in while the game was running.
38 | """
39 | r.game_joysticks = []
40 | r.game_js_names = {}
41 | r.game_js_ids = {}
42 | pygame.joystick.quit()
43 | pygame.joystick.init()
44 |
45 | if pygame.joystick.get_init():
46 | for i in range(pygame.joystick.get_count()):
47 | joy = pygame.joystick.Joystick(i)
48 | joy.init()
49 | n = joy.get_name()
50 | r.game_joysticks.append(joy)
51 | r.game_js_names[i] = n
52 | if n not in r.game_js_ids:
53 | r.game_js_ids[n] = i
54 |
55 |
56 | def get_axis(joystick, axis):
57 | """
58 | Return the position of a joystick axis as a float from ``-1`` to
59 | ``1``, where ``0`` is centered, ``-1`` is all the way to the left or
60 | up, and ``1`` is all the way to the right or down. Return ``0`` if
61 | the requested joystick or axis does not exist.
62 |
63 | Parameters:
64 |
65 | - ``joystick`` -- The number of the joystick to check, where ``0``
66 | is the first joystick, or the name of the joystick to check.
67 | - ``axis`` -- The number of the axis to check, where ``0`` is the
68 | first axis of the joystick.
69 | """
70 | joystick = get_id(joystick)
71 |
72 | if (joystick is not None and joystick < len(r.game_joysticks) and
73 | axis < r.game_joysticks[joystick].get_numaxes()):
74 | return max(-1.0, min(r.game_joysticks[joystick].get_axis(axis), 1.0))
75 | else:
76 | return 0
77 |
78 |
79 | def get_hat_x(joystick, hat):
80 | """
81 | Return the horizontal position of a joystick hat (d-pad). Can be
82 | ``-1`` (left), ``0`` (centered), or ``1`` (right). Return ``0`` if
83 | the requested joystick or hat does not exist.
84 |
85 | Parameters:
86 |
87 | - ``joystick`` -- The number of the joystick to check, where ``0``
88 | is the first joystick, or the name of the joystick to check.
89 | - ``hat`` -- The number of the hat to check, where ``0`` is the
90 | first hat of the joystick.
91 | """
92 | return r._get_hat(get_id(joystick), hat)[0]
93 |
94 |
95 | def get_hat_y(joystick, hat):
96 | """
97 | Return the vertical position of a joystick hat (d-pad). Can be
98 | ``-1`` (up), ``0`` (centered), or ``1`` (down). Return ``0`` if the
99 | requested joystick or hat does not exist.
100 |
101 | Parameters:
102 |
103 | - ``joystick`` -- The number of the joystick to check, where ``0``
104 | is the first joystick, or the name of the joystick to check.
105 | - ``hat`` -- The number of the hat to check, where ``0`` is the
106 | first hat of the joystick.
107 | """
108 | return -r._get_hat(get_id(joystick), hat)[1]
109 |
110 |
111 | def get_pressed(joystick, button):
112 | """
113 | Return whether or not a joystick button is pressed, or
114 | :const:`False` if the requested joystick or button does not exist.
115 |
116 | Parameters:
117 |
118 | - ``joystick`` -- The number of the joystick to check, where ``0``
119 | is the first joystick, or the name of the joystick to check.
120 | - ``button`` -- The number of the button to check, where ``0`` is
121 | the first button of the joystick.
122 | """
123 | joystick = get_id(joystick)
124 |
125 | if (joystick is not None and joystick < len(r.game_joysticks) and
126 | button < r.game_joysticks[joystick].get_numbuttons()):
127 | return r.game_joysticks[joystick].get_button(button)
128 | else:
129 | return False
130 |
131 |
132 | def get_value(joystick, input_type, input_id):
133 | """
134 | Return the value of any joystick control. This function makes it
135 | possible to treat all joystick inputs the same way, which can be
136 | used to simplify things like control customization.
137 |
138 | Parameters:
139 |
140 | - ``joystick`` -- The number of the joystick to check, where ``0``
141 | is the first joystick, or the name of the joystick to check.
142 | - ``input_type`` -- The type of joystick control to check. Can be
143 | one of the following:
144 |
145 | - ``"axis-"`` -- The tilt of an axis to the left or up as a float,
146 | where ``0`` is not tilted in this direction at all and ``1`` is
147 | tilted entirely in this direction.
148 | - ``"axis+"`` -- The tilt of an axis to the right or down as a
149 | float, where ``0`` is not tilted in this direction at all and
150 | ``1`` is tilted entirely in this direction.
151 | - ``"axis0"`` -- The distance of the tilt of an axis from the
152 | nearest extreme edge, where ``0`` is tilted entirely in a
153 | direction and ``1`` is completely centered.
154 | - ``"hat_left"`` -- Whether or not the left direction of a
155 | joystick hat (d-pad) is pressed.
156 | - ``"hat_right"`` -- Whether or not the right direction of a
157 | joystick hat (d-pad) is pressed.
158 | - ``"hat_center_x" -- Whether or not a joystick hat (d-pad) is
159 | horizontally centered.
160 | - ``"hat_up"`` -- Whether or not the up direction of a joystick
161 | hat (d-pad) is pressed.
162 | - ``"hat_down"`` -- Whether or not the down direction of a
163 | joystick hat (d-pad) is pressed.
164 | - ``"hat_center_y" -- Whether or not a joystick hat (d-pad) is
165 | vertically centered.
166 | - ``"button"`` -- Whether or not a joystick button is pressed.
167 |
168 | If an invalid type is specified, ``None`` is returned.
169 |
170 | - ``input_id`` -- The number of the control to check, where ``0`` is
171 | the first control of its type on the joystick.
172 | """
173 | if input_type == "axis-":
174 | return abs(min(0, get_axis(joystick, input_id)))
175 | elif input_type == "axis+":
176 | return abs(max(0, get_axis(joystick, input_id)))
177 | elif input_type == "axis0":
178 | return 1 - abs(get_axis(joystick, input_id))
179 | elif input_type == "hat_left":
180 | return get_hat_x(joystick, input_id) == -1
181 | elif input_type == "hat_right":
182 | return get_hat_x(joystick, input_id) == 1
183 | elif input_type == "hat_center_x":
184 | return get_hat_x(joystick, input_id) == 0
185 | elif input_type == "hat_up":
186 | return get_hat_y(joystick, input_id) == -1
187 | elif input_type == "hat_down":
188 | return get_hat_y(joystick, input_id) == 1
189 | elif input_type == "hat_center_y":
190 | return get_hat_y(joystick, input_id) == 0
191 | elif input_type == "button":
192 | return get_pressed(joystick, input_id)
193 | else:
194 | return None
195 |
196 |
197 | def get_joysticks():
198 | """Return the number of joysticks available."""
199 | return len(r.game_joysticks)
200 |
201 |
202 | def get_name(joystick):
203 | """
204 | Return the name of a joystick, or ``None`` if the requested joystick
205 | does not exist.
206 |
207 | Parameters:
208 |
209 | - ``joystick`` -- The number of the joystick to check, where ``0``
210 | is the first joystick, or the name of the joystick to check.
211 | """
212 | if isinstance(joystick, int):
213 | return r.game_js_names.setdefault(joystick)
214 | elif joystick in r.game_js_names.values():
215 | return joystick
216 | else:
217 | return None
218 |
219 |
220 | def get_id(joystick):
221 | """
222 | Return the number of a joystick, where ``0`` is the first joystick,
223 | or ``None`` if the requested joystick does not exist.
224 |
225 | Parameters:
226 |
227 | - ``joystick`` -- The number of the joystick to check, where ``0``
228 | is the first joystick, or the name of the joystick to check.
229 | """
230 | if not isinstance(joystick, int):
231 | return r.game_js_ids.setdefault(joystick)
232 | elif joystick in r.game_js_names:
233 | return joystick
234 | else:
235 | return None
236 |
237 |
238 | def get_axes(joystick):
239 | """
240 | Return the number of axes available on a joystick, or ``0`` if the
241 | requested joystick does not exist.
242 |
243 | Parameters:
244 |
245 | - ``joystick`` -- The number of the joystick to check, where ``0``
246 | is the first joystick, or the name of the joystick to check.
247 | """
248 | joystick = get_id(joystick)
249 |
250 | if joystick is not None and joystick < len(r.game_joysticks):
251 | return r.game_joysticks[joystick].get_numaxes()
252 | else:
253 | return 0
254 |
255 |
256 | def get_hats(joystick):
257 | """
258 | Return the number of hats (d-pads) available on a joystick, or ``0``
259 | if the requested joystick does not exist.
260 |
261 | Parameters:
262 |
263 | - ``joystick`` -- The number of the joystick to check, where ``0``
264 | is the first joystick, or the name of the joystick to check.
265 | """
266 | joystick = get_id(joystick)
267 |
268 | if joystick is not None and joystick < len(r.game_joysticks):
269 | return r.game_joysticks[joystick].get_numhats()
270 | else:
271 | return 0
272 |
273 |
274 | def get_trackballs(joystick):
275 | """
276 | Return the number of trackballs available on a joystick, or ``0`` if
277 | the requested joystick does not exist.
278 |
279 | Parameters:
280 |
281 | - ``joystick`` -- The number of the joystick to check, where ``0``
282 | is the first joystick, or the name of the joystick to check.
283 | """
284 | joystick = get_id(joystick)
285 |
286 | if joystick is not None and joystick < len(r.game_joysticks):
287 | return r.game_joysticks[joystick].get_numballs()
288 | else:
289 | return 0
290 |
291 |
292 | def get_buttons(joystick):
293 | """
294 | Return the number of buttons available on a joystick, or ``0`` if
295 | the requested joystick does not exist.
296 |
297 | Parameters:
298 |
299 | - ``joystick`` -- The number of the joystick to check, where ``0``
300 | is the first joystick, or the name of the joystick to check.
301 | """
302 | joystick = get_id(joystick)
303 |
304 | if joystick is not None and joystick < len(r.game_joysticks):
305 | return r.game_joysticks[joystick].get_numbuttons()
306 | else:
307 | return 0
308 |
--------------------------------------------------------------------------------
/sge/keyboard.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides functions related to keyboard input.
18 |
19 | As a general rule, any key press has two strings associated with it: an
20 | identifier string, and a unicode string. The identifier string is a
21 | consistent identifier for what the key is, consisting only of
22 | alphanumeric ASCII text. The unicode string is the text associated with
23 | the key press; typically this is an ASCII character printed on the key,
24 | but in some cases (e.g. when an input method is used), it could be any
25 | kind of text. As a general rule, the unicode string should always be
26 | used for text entry, while the identifier string should be used for all
27 | other purposes.
28 |
29 | The table below lists all standard keys along with their corresponding
30 | identifier and unicode strings. Note that SGE implementations are not
31 | necessarily required to support recognizing all of them, although they
32 | are strongly encouraged to do so. Any key not found on this table, if
33 | detected, will be arbitrarily but consistently assigned an identifier
34 | string beginning with ``"undef_"``.
35 |
36 | ==================== ======================= ==============
37 | Key Name Identifier String Unicode String
38 | ==================== ======================= ==============
39 | 0 ``"0"`` ``"0"``
40 | 1 ``"1"`` ``"1"``
41 | 2 ``"2"`` ``"2"``
42 | 3 ``"3"`` ``"3"``
43 | 4 ``"4"`` ``"4"``
44 | 5 ``"5"`` ``"5"``
45 | 6 ``"6"`` ``"6"``
46 | 7 ``"7"`` ``"7"``
47 | 8 ``"8"`` ``"8"``
48 | 9 ``"9"`` ``"9"``
49 | A ``"a"`` ``"a"``
50 | B ``"b"`` ``"b"``
51 | C ``"c"`` ``"c"``
52 | D ``"d"`` ``"d"``
53 | E ``"e"`` ``"e"``
54 | F ``"f"`` ``"f"``
55 | G ``"g"`` ``"g"``
56 | H ``"h"`` ``"h"``
57 | I ``"i"`` ``"i"``
58 | J ``"j"`` ``"j"``
59 | K ``"k"`` ``"k"``
60 | L ``"l"`` ``"l"``
61 | M ``"m"`` ``"m"``
62 | N ``"n"`` ``"n"``
63 | O ``"o"`` ``"o"``
64 | P ``"p"`` ``"p"``
65 | Q ``"q"`` ``"q"``
66 | R ``"r"`` ``"r"``
67 | S ``"s"`` ``"s"``
68 | T ``"t"`` ``"t"``
69 | U ``"u"`` ``"u"``
70 | V ``"v"`` ``"v"``
71 | W ``"w"`` ``"w"``
72 | X ``"x"`` ``"x"``
73 | Y ``"y"`` ``"y"``
74 | Z ``"z"`` ``"z"``
75 | Period ``"period"`` ``"."``
76 | Comma ``"comma"`` ``","``
77 | Less Than ``"less_than"`` ``"<"``
78 | Greater Than ``"greater_than"`` ``">"``
79 | Forward Slash ``"slash"`` ``"/"``
80 | Question Mark ``"question"`` ``"?"``
81 | Apostrophe ``"apostrophe"`` ``"'"``
82 | Quotation Mark ``"quote"`` ``'"'``
83 | Colon ``"colon"`` ``":"``
84 | Semicolon ``"semicolon"`` ``";"``
85 | Exclamation Point ``"exclamation"`` ``"!"``
86 | At ``"at"`` ``"@"``
87 | Hash ``"hash"`` ``"#"``
88 | Dollar Sign ``"dollar"`` ``"$"``
89 | Percent Sign ``"percent"`` ``"%"``
90 | Carat ``"carat"`` ``"^"``
91 | Ampersand ``"ampersand"`` ``"&"``
92 | Asterisk ``"asterisk"`` ``"*"``
93 | Left Parenthesis ``"parenthesis_left"`` ``"("``
94 | Right Parenthesis ``"parenthesis_right"`` ``")"``
95 | Hyphen ``"hyphen"`` ``"-"``
96 | Underscore ``"underscore"`` ``"_"``
97 | Plus Sign ``"plus"`` ``"+"``
98 | Equals Sign ``"equals"`` ``"="``
99 | Left Bracket ``"bracket_left"`` ``"["``
100 | Right Bracket ``"bracket_right"`` ``"]"``
101 | Left Brace ``"brace_left"`` ``"{"``
102 | Right Brace ``"brace_right"`` ``"}"``
103 | Backslash ``"backslash"`` ``"\\\\"``
104 | Backtick ``"backtick"`` ``"`"``
105 | Euro ``"euro"`` ``"\\u20ac"``
106 | Keypad 0 ``"kp_0"`` ``"0"``
107 | Keypad 1 ``"kp_1"`` ``"1"``
108 | Keypad 2 ``"kp_2"`` ``"2"``
109 | Keypad 3 ``"kp_3"`` ``"3"``
110 | Keypad 4 ``"kp_4"`` ``"4"``
111 | Keypad 5 ``"kp_5"`` ``"5"``
112 | Keypad 6 ``"kp_6"`` ``"6"``
113 | Keypad 7 ``"kp_7"`` ``"7"``
114 | Keypad 8 ``"kp_8"`` ``"8"``
115 | Keypad 9 ``"kp_9"`` ``"9"``
116 | Keypad Decimal Point ``"kp_point"`` ``"."``
117 | Keypad Plus ``"kp_plus"`` ``"+"``
118 | Keypad Minus ``"kp_minus"`` ``"-"``
119 | Keypad Multiply ``"kp_multiply"`` ``"*"``
120 | Keypad Divide ``"kp_divide"`` ``"/"``
121 | Keypad Equals ``"kp_equals"`` ``"="``
122 | Keypad Enter ``"kp_enter"`` ``"\\n"``
123 | Left Arrow ``"left"`` ``""``
124 | Right Arrow ``"right"`` ``""``
125 | Up Arrow ``"up"`` ``""``
126 | Down Arrow ``"down"`` ``""``
127 | Home ``"home"`` ``""``
128 | End ``"end"`` ``""``
129 | Page Up ``"pageup"`` ``""``
130 | Page Down ``"pagedown"`` ``""``
131 | Tab ``"tab"`` ``"\\t"``
132 | Space Bar ``"space"`` ``" "``
133 | Enter/Return ``"enter"`` ``"\\n"``
134 | Backspace ``"backspace"`` ``"\\b"``
135 | Delete ``"delete"`` ``""``
136 | Left Shift ``"shift_left"`` ``""``
137 | Right Shift ``"shift_right"`` ``""``
138 | Left Ctrl ``"ctrl_left"`` ``""``
139 | Right Ctrl ``"ctrl_right"`` ``""``
140 | Left Alt ``"alt_left"`` ``""``
141 | Right Alt ``"alt_right"`` ``""``
142 | Left Meta ``"meta_left"`` ``""``
143 | Right Meta ``"meta_right"`` ``""``
144 | Caps Lock ``"caps_lock"`` ``""``
145 | Esc ``"escape"`` ``""``
146 | Num Lock ``"num_lock"`` ``""``
147 | Scroll Lock ``"scroll_lock"`` ``""``
148 | Break ``"break"`` ``""``
149 | Insert ``"insert"`` ``""``
150 | Pause ``"pause"`` ``""``
151 | Print Screen ``"print_screen"`` ``""``
152 | SysRq ``"sysrq"`` ``""``
153 | F1 ``"f1"`` ``""``
154 | F2 ``"f2"`` ``""``
155 | F3 ``"f3"`` ``""``
156 | F4 ``"f4"`` ``""``
157 | F5 ``"f5"`` ``""``
158 | F6 ``"f6"`` ``""``
159 | F7 ``"f7"`` ``""``
160 | F8 ``"f8"`` ``""``
161 | F9 ``"f9"`` ``""``
162 | F10 ``"f10"`` ``""``
163 | F11 ``"f11"`` ``""``
164 | F12 ``"f12"`` ``""``
165 | ==================== ======================= ==============
166 | """
167 |
168 |
169 | __all__ = ["get_pressed", "get_modifier", "get_focused", "set_repeat",
170 | "get_repeat_enabled", "get_repeat_interval", "get_repeat_delay"]
171 |
172 |
173 | import pygame
174 |
175 | import sge
176 |
177 |
178 | _repeat_enabled = False
179 |
180 |
181 | def get_pressed(key):
182 | """
183 | Return whether or not a key is pressed.
184 |
185 | Parameters:
186 |
187 | - ``key`` -- The identifier string of the modifier key to check; see
188 | the table in the documentation for :mod:`sge.keyboard`.
189 | """
190 | key = key.lower()
191 | if key in sge.KEYS:
192 | return pygame.key.get_pressed()[sge.KEYS[key]]
193 | else:
194 | return False
195 |
196 |
197 | def get_modifier(key):
198 | """
199 | Return whether or not a modifier key is being held.
200 |
201 | Parameters:
202 |
203 | - ``key`` -- The identifier string of the modifier key to check; see
204 | the table below.
205 |
206 | ================= =================
207 | Modifier Key Name Identifier String
208 | ================= =================
209 | Alt ``"alt"``
210 | Left Alt ``"alt_left"``
211 | Right Alt ``"alt_right"``
212 | Ctrl ``"ctrl"``
213 | Left Ctrl ``"ctrl_left"``
214 | Right Ctrl ``"ctrl_right"``
215 | Meta ``"meta"``
216 | Left Meta ``"meta_left"``
217 | Right Meta ``"meta_right"``
218 | Shift ``"shift"``
219 | Left Shift ``"shift_left"``
220 | Right Shift ``"shift_right"``
221 | Mode ``"mode"``
222 | Caps Lock ``"caps_lock"``
223 | Num Lock ``"num_lock"``
224 | ================= =================
225 | """
226 | key = key.lower()
227 | if key in sge.MODS:
228 | return pygame.key.get_mods() & sge.MODS[key]
229 | else:
230 | return False
231 |
232 |
233 | def get_focused():
234 | """Return whether or not the game has keyboard focus."""
235 | return pygame.key.get_focused()
236 |
237 |
238 | def set_repeat(enabled=True, interval=0, delay=0):
239 | """
240 | Set repetition of key press events.
241 |
242 | Parameters:
243 |
244 | - ``enabled`` -- Whether or not to enable repetition of key press
245 | events.
246 | - ``interval`` -- The time in milliseconds in between each repeated
247 | key press event.
248 | - ``delay`` -- The time in milliseconds to wait after the first key
249 | press event before repeating key press events.
250 |
251 | If ``enabled`` is set to true, this causes a key being held down to
252 | generate additional key press events as long as it remains held
253 | down.
254 | """
255 | global _repeat_enabled
256 | _repeat_enabled = enabled
257 | if enabled:
258 | pygame.key.set_repeat(delay, interval)
259 | else:
260 | pygame.key.set_repeat()
261 |
262 |
263 | def get_repeat_enabled():
264 | """
265 | Return whether or not repetition of key press events is enabled.
266 |
267 | See the documentation for :func:`sge.keyboard.set_repeat` for more
268 | information.
269 | """
270 | return _repeat_enabled
271 |
272 |
273 | def get_repeat_interval():
274 | """
275 | Return the interval in between each repeated key press event.
276 |
277 | See the documentation for :func:`sge.keyboard.set_repeat` for more
278 | information.
279 | """
280 | return pygame.key.get_repeat()[1]
281 |
282 |
283 | def get_repeat_delay():
284 | """
285 | Return the delay before repeating key press events.
286 |
287 | See the documentation for :func:`sge.keyboard.set_repeat` for more
288 | information.
289 | """
290 | return pygame.key.get_repeat()[0]
291 |
--------------------------------------------------------------------------------
/sge/mouse.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides functions related to the mouse input.
18 |
19 | Some other mouse functionalities are provided through attributes of
20 | :attr:`sge.game.mouse`. These attributes are listed below.
21 |
22 | The mouse can be in either absolute or relative mode. In absolute mode,
23 | the mouse has a position. In relative mode, the mouse only moves.
24 | Which mode the mouse is in depends on the values of
25 | :attr:`sge.game.grab_input` and :attr:`sge.game.mouse.visible`.
26 |
27 | .. attribute:: sge.game.mouse.x
28 | sge.game.mouse.y
29 |
30 | If the mouse is in absolute mode and within a view port, these
31 | attributes indicate the
32 | position of the mouse in the room, based on its proximity to the view
33 | it is in. Otherwise, they will return ``-1``.
34 |
35 | These attributes can be assigned to safely, but doing so will not
36 | have any effect.
37 |
38 | .. attribute:: sge.game.mouse.z
39 |
40 | The Z-axis position of the mouse cursor's projection in relation to
41 | other window projections. The default value is ``10000``.
42 |
43 | .. attribute:: sge.game.mouse.sprite
44 |
45 | Determines what sprite will be used to represent the mouse cursor.
46 | Set to ``None`` for the default mouse cursor.
47 |
48 | .. attribute:: sge.game.mouse.visible
49 |
50 | Controls whether or not the mouse cursor is visible. If this is
51 | :const:`False` and :attr:`sge.game.grab_input` is :const:`True`, the
52 | mouse will be in relative mode. Otherwise, the mouse will be in
53 | absolute mode.
54 | """
55 |
56 |
57 | __all__ = ["get_pressed", "get_x", "get_y", "set_x", "set_y"]
58 |
59 |
60 | import pygame
61 |
62 | import sge
63 | from sge import r
64 |
65 |
66 | def get_pressed(button):
67 | """
68 | Return whether or not a mouse button is pressed.
69 |
70 | See the documentation for :class:`sge.input.MouseButtonPress` for
71 | more information.
72 | """
73 | b = {"left": 0, "middle": 1, "right": 2}.setdefault(button.lower())
74 | if b is not None:
75 | return pygame.mouse.get_pressed()[b]
76 | else:
77 | return False
78 |
79 |
80 | def get_x():
81 | """
82 | Return the horizontal location of the mouse cursor.
83 |
84 | The location returned is relative to the window, excluding any
85 | scaling, pillarboxes, and letterboxes. If the mouse is in
86 | relative mode, this function returns ``None``.
87 | """
88 | if sge.game.grab_input and not sge.game.mouse.visible:
89 | return None
90 | else:
91 | return (pygame.mouse.get_pos()[0] - r.game_x) / r.game_xscale
92 |
93 |
94 | def get_y():
95 | """
96 | Return the vertical location of the mouse cursor.
97 |
98 | The location returned is relative to the window, excluding any
99 | scaling, pillarboxes, and letterboxes. If the mouse is in
100 | relative mode, this function returns ``None``.
101 | """
102 | if sge.game.grab_input and not sge.game.mouse.visible:
103 | return None
104 | else:
105 | return (pygame.mouse.get_pos()[1] - r.game_y) / r.game_yscale
106 |
107 |
108 | def set_x(value):
109 | """
110 | Set the horizontal location of the mouse cursor.
111 |
112 | The location returned is relative to the window, excluding any
113 | scaling, pillarboxes, and letterboxes. If the mouse is in
114 | relative mode, this function has no effect.
115 | """
116 | if not sge.game.grab_input or sge.game.mouse.visible:
117 | pygame.mouse.set_pos(value * r.game_xscale + r.game_x,
118 | pygame.mouse.get_pos()[1])
119 |
120 |
121 | def set_y(value):
122 | """
123 | Set the vertical location of the mouse cursor.
124 |
125 | The location returned is relative to the window, excluding any
126 | scaling, pillarboxes, and letterboxes. If the mouse is in
127 | relative mode, this function has no effect.
128 | """
129 | if not sge.game.grab_input or sge.game.mouse.visible:
130 | pygame.mouse.set_pos(pygame.mouse.get_pos()[0],
131 | value * r.game_yscale + r.game_y)
132 |
--------------------------------------------------------------------------------
/sge/s.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides several variables which represent particular
18 | important strings. The purpose of these variables (listed below) is to
19 | make typos more obvious.
20 |
21 | The values of all of these variables are their names as strings. If a
22 | variable name starts with an underscore, its value excludes this
23 | preceding underscore. For example, a variable called ``spam`` would
24 | have a value of ``"spam"``, and a variable called ``_1984`` would have a
25 | value of ``"1984"``.
26 |
27 | This module only contains these variable assignments and nothing else,
28 | so if it is useful to you, you can add assignments to this module as
29 | long as said assignments conform with the specification above.
30 |
31 | .. note::
32 |
33 | This module does not use the convention of marking "private" members
34 | with a leading underscore; rather, a leading underscore is used to
35 | ensure that strings starting with numeric characters can be
36 | supported. All variables in this module are available for use.
37 |
38 | .. data:: sge.s._0
39 | .. data:: sge.s._1
40 | .. data:: sge.s._2
41 | .. data:: sge.s._3
42 | .. data:: sge.s._4
43 | .. data:: sge.s._5
44 | .. data:: sge.s._6
45 | .. data:: sge.s._7
46 | .. data:: sge.s._8
47 | .. data:: sge.s._9
48 | .. data:: sge.s.a
49 | .. data:: sge.s.b
50 | .. data:: sge.s.c
51 | .. data:: sge.s.d
52 | .. data:: sge.s.e
53 | .. data:: sge.s.f
54 | .. data:: sge.s.g
55 | .. data:: sge.s.h
56 | .. data:: sge.s.i
57 | .. data:: sge.s.j
58 | .. data:: sge.s.k
59 | .. data:: sge.s.l
60 | .. data:: sge.s.m
61 | .. data:: sge.s.n
62 | .. data:: sge.s.o
63 | .. data:: sge.s.p
64 | .. data:: sge.s.q
65 | .. data:: sge.s.r
66 | .. data:: sge.s.s
67 | .. data:: sge.s.t
68 | .. data:: sge.s.u
69 | .. data:: sge.s.v
70 | .. data:: sge.s.w
71 | .. data:: sge.s.x
72 | .. data:: sge.s.y
73 | .. data:: sge.s.z
74 | .. data:: sge.s._break
75 | .. data:: sge.s.alt_left
76 | .. data:: sge.s.alt_right
77 | .. data:: sge.s.ampersand
78 | .. data:: sge.s.apostrophe
79 | .. data:: sge.s.aqua
80 | .. data:: sge.s.asterisk
81 | .. data:: sge.s.at
82 | .. data:: sge.s.axis0
83 | .. data:: sge.s.backslash
84 | .. data:: sge.s.backspace
85 | .. data:: sge.s.backtick
86 | .. data:: sge.s.black
87 | .. data:: sge.s.blue
88 | .. data:: sge.s.bottom
89 | .. data:: sge.s.brace_left
90 | .. data:: sge.s.brace_right
91 | .. data:: sge.s.bracket_left
92 | .. data:: sge.s.bracket_right
93 | .. data:: sge.s.button
94 | .. data:: sge.s.caps_lock
95 | .. data:: sge.s.carat
96 | .. data:: sge.s.center
97 | .. data:: sge.s.colon
98 | .. data:: sge.s.comma
99 | .. data:: sge.s.ctrl_left
100 | .. data:: sge.s.ctrl_right
101 | .. data:: sge.s.delete
102 | .. data:: sge.s.dissolve
103 | .. data:: sge.s.dollar
104 | .. data:: sge.s.down
105 | .. data:: sge.s.end
106 | .. data:: sge.s.enter
107 | .. data:: sge.s.equals
108 | .. data:: sge.s.escape
109 | .. data:: sge.s.euro
110 | .. data:: sge.s.exclamation
111 | .. data:: sge.s.extra1
112 | .. data:: sge.s.extra2
113 | .. data:: sge.s.f0
114 | .. data:: sge.s.f1
115 | .. data:: sge.s.f2
116 | .. data:: sge.s.f3
117 | .. data:: sge.s.f4
118 | .. data:: sge.s.f5
119 | .. data:: sge.s.f6
120 | .. data:: sge.s.f7
121 | .. data:: sge.s.f8
122 | .. data:: sge.s.f9
123 | .. data:: sge.s.f10
124 | .. data:: sge.s.f11
125 | .. data:: sge.s.f12
126 | .. data:: sge.s.fade
127 | .. data:: sge.s.fuchsia
128 | .. data:: sge.s.gray
129 | .. data:: sge.s.greater_than
130 | .. data:: sge.s.green
131 | .. data:: sge.s.hash
132 | .. data:: sge.s.hat_center_x
133 | .. data:: sge.s.hat_center_y
134 | .. data:: sge.s.hat_down
135 | .. data:: sge.s.hat_left
136 | .. data:: sge.s.hat_right
137 | .. data:: sge.s.hat_up
138 | .. data:: sge.s.hexagonal
139 | .. data:: sge.s.home
140 | .. data:: sge.s.hyphen
141 | .. data:: sge.s.insert
142 | .. data:: sge.s.iris_in
143 | .. data:: sge.s.iris_out
144 | .. data:: sge.s.isohex
145 | .. data:: sge.s.isometric
146 | .. data:: sge.s.kp_0
147 | .. data:: sge.s.kp_1
148 | .. data:: sge.s.kp_2
149 | .. data:: sge.s.kp_3
150 | .. data:: sge.s.kp_4
151 | .. data:: sge.s.kp_5
152 | .. data:: sge.s.kp_6
153 | .. data:: sge.s.kp_7
154 | .. data:: sge.s.kp_8
155 | .. data:: sge.s.kp_9
156 | .. data:: sge.s.kp_divide
157 | .. data:: sge.s.kp_enter
158 | .. data:: sge.s.kp_equals
159 | .. data:: sge.s.kp_minus
160 | .. data:: sge.s.kp_multiply
161 | .. data:: sge.s.kp_plus
162 | .. data:: sge.s.kp_point
163 | .. data:: sge.s.left
164 | .. data:: sge.s.less_than
165 | .. data:: sge.s.lime
166 | .. data:: sge.s.maroon
167 | .. data:: sge.s.meta_left
168 | .. data:: sge.s.meta_right
169 | .. data:: sge.s.middle
170 | .. data:: sge.s.navy
171 | .. data:: sge.s.noblur
172 | .. data:: sge.s.num_lock
173 | .. data:: sge.s.olive
174 | .. data:: sge.s.orthogonal
175 | .. data:: sge.s.pagedown
176 | .. data:: sge.s.pageup
177 | .. data:: sge.s.parenthesis_left
178 | .. data:: sge.s.parenthesis_right
179 | .. data:: sge.s.pause
180 | .. data:: sge.s.percent
181 | .. data:: sge.s.period
182 | .. data:: sge.s.pixelate
183 | .. data:: sge.s.plus
184 | .. data:: sge.s.print_screen
185 | .. data:: sge.s.purple
186 | .. data:: sge.s.question
187 | .. data:: sge.s.quote
188 | .. data:: sge.s.red
189 | .. data:: sge.s.right
190 | .. data:: sge.s.scroll_lock
191 | .. data:: sge.s.semicolon
192 | .. data:: sge.s.shift_left
193 | .. data:: sge.s.shift_right
194 | .. data:: sge.s.silver
195 | .. data:: sge.s.slash
196 | .. data:: sge.s.smooth
197 | .. data:: sge.s.space
198 | .. data:: sge.s.sysrq
199 | .. data:: sge.s.tab
200 | .. data:: sge.s.teal
201 | .. data:: sge.s.top
202 | .. data:: sge.s.trackball_down
203 | .. data:: sge.s.trackball_left
204 | .. data:: sge.s.trackball_right
205 | .. data:: sge.s.trackball_up
206 | .. data:: sge.s.underscore
207 | .. data:: sge.s.up
208 | .. data:: sge.s.wheel_down
209 | .. data:: sge.s.wheel_left
210 | .. data:: sge.s.wheel_right
211 | .. data:: sge.s.wheel_up
212 | .. data:: sge.s.white
213 | .. data:: sge.s.wipe_down
214 | .. data:: sge.s.wipe_downleft
215 | .. data:: sge.s.wipe_downright
216 | .. data:: sge.s.wipe_left
217 | .. data:: sge.s.wipe_matrix
218 | .. data:: sge.s.wipe_right
219 | .. data:: sge.s.wipe_up
220 | .. data:: sge.s.wipe_upleft
221 | .. data:: sge.s.wipe_upright
222 | .. data:: sge.s.yellow
223 | """
224 |
225 |
226 | # Alignment indicators
227 | left = "left"
228 | right = "right"
229 | center = "center"
230 | top = "top"
231 | bottom = "bottom"
232 | middle = "middle"
233 |
234 | # Color names
235 | white = "white"
236 | silver = "silver"
237 | gray = "gray"
238 | black = "black"
239 | red = "red"
240 | lime = "lime"
241 | blue = "blue"
242 | maroon = "maroon"
243 | green = "green"
244 | navy = "navy"
245 | yellow = "yellow"
246 | fuchsia = "fuchsia"
247 | aqua = "aqua"
248 | olive = "olive"
249 | purple = "purple"
250 | teal = "teal"
251 |
252 | # Scale methods
253 | noblur = "noblur"
254 | smooth = "smooth"
255 |
256 | # Key names
257 | _0 = "0"
258 | _1 = "1"
259 | _2 = "2"
260 | _3 = "3"
261 | _4 = "4"
262 | _5 = "5"
263 | _6 = "6"
264 | _7 = "7"
265 | _8 = "8"
266 | _9 = "9"
267 | a = "a"
268 | b = "b"
269 | c = "c"
270 | d = "d"
271 | e = "e"
272 | f = "f"
273 | g = "g"
274 | h = "h"
275 | i = "i"
276 | j = "j"
277 | k = "k"
278 | l = "l"
279 | m = "m"
280 | n = "n"
281 | o = "o"
282 | p = "p"
283 | q = "q"
284 | r = "r"
285 | s = "s"
286 | t = "t"
287 | u = "u"
288 | v = "v"
289 | w = "w"
290 | x = "x"
291 | y = "y"
292 | z = "z"
293 | period = "period"
294 | comma = "comma"
295 | less_than = "less_than"
296 | greater_than = "greater_than"
297 | slash = "slash"
298 | question = "question"
299 | apostrophe = "apostrophe"
300 | quote = "quote"
301 | colon = "colon"
302 | semicolon = "semicolon"
303 | exclamation = "exclamation"
304 | at = "at"
305 | hash = "hash"
306 | dollar = "dollar"
307 | percent = "percent"
308 | carat = "carat"
309 | ampersand = "ampersand"
310 | asterisk = "asterisk"
311 | parenthesis_left = "parenthesis_left"
312 | parenthesis_right = "parenthesis_right"
313 | hyphen = "hyphen"
314 | underscore = "underscore"
315 | plus = "plus"
316 | equals = "equals"
317 | bracket_left = "bracket_left"
318 | bracket_right = "bracket_right"
319 | brace_left = "brace_left"
320 | brace_right = "brace_right"
321 | backslash = "backslash"
322 | backtick = "backtick"
323 | euro = "euro"
324 | kp_0 = "kp_0"
325 | kp_1 = "kp_1"
326 | kp_2 = "kp_2"
327 | kp_3 = "kp_3"
328 | kp_4 = "kp_4"
329 | kp_5 = "kp_5"
330 | kp_6 = "kp_6"
331 | kp_7 = "kp_7"
332 | kp_8 = "kp_8"
333 | kp_9 = "kp_9"
334 | kp_point = "kp_point"
335 | kp_plus = "kp_plus"
336 | kp_minus = "kp_minus"
337 | kp_multiply = "kp_multiply"
338 | kp_divide = "kp_divide"
339 | kp_equals = "kp_equals"
340 | kp_enter = "kp_enter"
341 | left = "left"
342 | right = "right"
343 | up = "up"
344 | down = "down"
345 | home = "home"
346 | end = "end"
347 | pageup = "pageup"
348 | pagedown = "pagedown"
349 | tab = "tab"
350 | space = "space"
351 | enter = "enter"
352 | backspace = "backspace"
353 | delete = "delete"
354 | shift_left = "shift_left"
355 | shift_right = "shift_right"
356 | ctrl_left = "ctrl_left"
357 | ctrl_right = "ctrl_right"
358 | alt_left = "alt_left"
359 | alt_right = "alt_right"
360 | meta_left = "meta_left"
361 | meta_right = "meta_right"
362 | caps_lock = "caps_lock"
363 | escape = "escape"
364 | num_lock = "num_lock"
365 | scroll_lock = "scroll_lock"
366 | _break = "break"
367 | insert = "insert"
368 | pause = "pause"
369 | print_screen = "print_screen"
370 | sysrq = "sysrq"
371 | f0 = "f0"
372 | f1 = "f1"
373 | f2 = "f2"
374 | f3 = "f3"
375 | f4 = "f4"
376 | f5 = "f5"
377 | f6 = "f6"
378 | f7 = "f7"
379 | f8 = "f8"
380 | f9 = "f9"
381 | f10 = "f10"
382 | f11 = "f11"
383 | f12 = "f12"
384 |
385 | # Mouse buttons
386 | left = "left"
387 | right = "right"
388 | middle = "middle"
389 | wheel_up = "wheel_up"
390 | wheel_down = "wheel_down"
391 | wheel_left = "wheel_left"
392 | wheel_right = "wheel_right"
393 | extra1 = "extra1"
394 | extra2 = "extra2"
395 |
396 | # Joystick input types
397 | # "axis+" and "axis-" unfortunately must be excluded.
398 | axis0 = "axis0"
399 | hat_left = "hat_left"
400 | hat_right = "hat_right"
401 | hat_center_x = "hat_center_x"
402 | hat_up = "hat_up"
403 | hat_down = "hat_down"
404 | hat_center_y = "hat_center_y"
405 | trackball_left = "trackball_left"
406 | trackball_right = "trackball_right"
407 | trackball_up = "trackball_up"
408 | trackball_down = "trackball_down"
409 | button = "button"
410 |
411 | # Transitions
412 | fade = "fade"
413 | dissolve = "dissolve"
414 | pixelate = "pixelate"
415 | wipe_left = "wipe_left"
416 | wipe_right = "wipe_right"
417 | wipe_up = "wipe_up"
418 | wipe_down = "wipe_down"
419 | wipe_upleft = "wipe_upleft"
420 | wipe_upright = "wipe_upright"
421 | wipe_downleft = "wipe_downleft"
422 | wipe_downright = "wipe_downright"
423 | wipe_matrix = "wipe_matrix"
424 | iris_in = "iris_in"
425 | iris_out = "iris_out"
426 |
427 | # Tile grids
428 | hexagonal = "hexagonal"
429 | isohex = "isohex"
430 | isometric = "isometric"
431 | orthogonal = "orthogonal"
432 |
433 |
--------------------------------------------------------------------------------
/sge/snd.py:
--------------------------------------------------------------------------------
1 | # This file is part of the Pygame SGE.
2 | #
3 | # The Pygame SGE is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU Lesser General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # The Pygame SGE is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License
14 | # along with the Pygame SGE. If not, see .
15 |
16 | """
17 | This module provides classes related to the sound system.
18 | """
19 |
20 |
21 | __all__ = ["Sound", "Music", "stop_all"]
22 |
23 |
24 | import os
25 | import random
26 | import warnings
27 |
28 | import pygame
29 |
30 | import sge
31 | from sge import r
32 | from sge.r import _get_channel, _release_channel
33 |
34 |
35 | class Sound:
36 |
37 | """
38 | This class stores and plays sound effects. Note that this is
39 | inefficient for large music files; for those, use
40 | :class:`sge.snd.Music` instead.
41 |
42 | What sound formats are supported depends on the implementation of
43 | the SGE, but sound formats that are generally a good choice are Ogg
44 | Vorbis and uncompressed WAV. See the implementation-specific
45 | information for a full list of supported formats.
46 |
47 | .. attribute:: volume
48 |
49 | The volume of the sound as a value from ``0`` to ``1`` (``0`` for
50 | no sound, ``1`` for maximum volume).
51 |
52 | .. attribute:: max_play
53 |
54 | The maximum number of instances of this sound playing permitted.
55 | If a sound is played while this number of the instances of the
56 | same sound are already playing, one of the already playing sounds
57 | will be stopped before playing the new instance. Set to ``None``
58 | for no limit.
59 |
60 | .. attribute:: parent
61 |
62 | Indicates another sound which is treated as being the same sound
63 | as this one for the purpose of determining whether or not, and
64 | how many times, the sound is playing. Set to ``None`` for no
65 | parent.
66 |
67 | If the sound has a parent, :attr:`max_play` will have no effect
68 | and instead the parent sound's :attr:`max_play` will apply to
69 | both the parent sound and this sound.
70 |
71 | .. warning::
72 |
73 | It is acceptable for a sound to both be a parent and have a
74 | parent. However, there MUST be a parent at the top which has
75 | no parent. The behavior of circular parenting, such as making
76 | two sounds parents of each other, is undefined.
77 |
78 | .. attribute:: fname
79 |
80 | The file name of the sound given when it was created.
81 | (Read-only)
82 |
83 | .. attribute:: length
84 |
85 | The length of the sound in milliseconds. (Read-only)
86 |
87 | .. attribute:: playing
88 |
89 | The number of instances of this sound playing. (Read-only)
90 |
91 | .. attribute:: rd
92 |
93 | Reserved dictionary for internal use by the SGE. (Read-only)
94 | """
95 |
96 | @property
97 | def max_play(self):
98 | return len(self.rd["channels"]) if self.rd["channels"] else None
99 |
100 | @max_play.setter
101 | def max_play(self, value):
102 | self.__max_play = value
103 |
104 | if value is None:
105 | value = 0
106 |
107 | if self.__sound is not None and self.parent is None:
108 | value = max(0, value)
109 | while len(self.rd["channels"]) < value:
110 | self.rd["channels"].append(_get_channel())
111 | while len(self.rd["channels"]) > value:
112 | _release_channel(self.rd["channels"].pop(-1))
113 |
114 | @property
115 | def parent(self):
116 | return self.__parent
117 |
118 | @parent.setter
119 | def parent(self, value):
120 | if value != self.__parent:
121 | self.__parent = value
122 | if value is None:
123 | self.rd["channels"] = []
124 | self.max_play = self.__max_play
125 | else:
126 | while self.rd["channels"]:
127 | _release_channel(self.rd["channels"].pop(-1))
128 | self.rd["channels"] = value.rd["channels"]
129 |
130 | @property
131 | def length(self):
132 | if self.__sound is not None:
133 | return self.__sound.get_length() * 1000
134 | else:
135 | return 0
136 |
137 | @property
138 | def playing(self):
139 | n = 0
140 | for channel in self.rd["channels"] + self.__temp_channels:
141 | if channel.get_busy():
142 | n += 1
143 |
144 | return n
145 |
146 | def __init__(self, fname, volume=1, max_play=1, parent=None):
147 | """
148 | Parameters:
149 |
150 | - ``fname`` -- The path to the sound file. If set to
151 | ``None``, this object will not actually play any sound. If
152 | this is neither a valid sound file nor ``None``,
153 | :exc:`FileNotFoundError` is raised.
154 |
155 | All other arguments set the respective initial attributes of the
156 | sound. See the documentation for :class:`sge.snd.Sound` for
157 | more information.
158 | """
159 | self.rd = {}
160 | errlist = []
161 |
162 | if fname is not None and pygame.mixer.get_init():
163 | try:
164 | self.__sound = pygame.mixer.Sound(fname)
165 | except pygame.error as e:
166 | fname = None
167 | self.__sound = None
168 | raise FileNotFoundError(e)
169 | else:
170 | self.__sound = None
171 |
172 | self.__sound_init = r.sound_init
173 | self.rd["channels"] = []
174 | self.__temp_channels = []
175 | self.fname = fname
176 | self.volume = volume
177 | self.__parent = None
178 | if parent is None:
179 | self.max_play = max_play
180 | else:
181 | self.__max_play = max_play
182 | self.parent = parent
183 |
184 | def play(self, loops=1, volume=1, balance=0, maxtime=None,
185 | fade_time=None, force=True):
186 | """
187 | Play the sound.
188 |
189 | Parameters:
190 |
191 | - ``loops`` -- The number of times to play the sound; set to
192 | ``None`` or ``0`` to loop indefinitely.
193 | - ``volume`` -- The volume to play the sound at as a factor
194 | of :attr:`self.volume` (``0`` for no sound, ``1`` for
195 | :attr:`self.volume`).
196 | - ``balance`` -- The balance of the sound effect on stereo
197 | speakers as a float from ``-1`` to ``1``, where ``0`` is
198 | centered (full volume in both speakers), ``1`` is entirely in
199 | the right speaker, and ``-1`` is entirely in the left speaker.
200 | - ``maxtime`` -- The maximum amount of time to play the sound in
201 | milliseconds; set to ``None`` for no limit.
202 | - ``fade_time`` -- The time in milliseconds over which to fade
203 | the sound in; set to ``None`` or ``0`` to immediately play the
204 | sound at full volume.
205 | - ``force`` -- Whether or not the sound should be played even if
206 | it is already playing the maximum number of times. If set to
207 | :const:`True` and the sound is already playing the maximum
208 | number of times, one of the instances of the sound already
209 | playing will be stopped.
210 | """
211 | if not pygame.mixer.get_init():
212 | return
213 |
214 | if self.__sound_init < r.sound_init:
215 | if self.fname is not None:
216 | try:
217 | self.__sound = pygame.mixer.Sound(self.fname)
218 | except pygame.error as e:
219 | self.__sound = None
220 | else:
221 | self.__sound = None
222 |
223 | if self.__sound is None:
224 | return
225 |
226 | if not loops:
227 | loops = 0
228 | if maxtime is None:
229 | maxtime = 0
230 | if fade_time is None:
231 | fade_time = 0
232 |
233 | # Adjust for the way Pygame does repeats
234 | loops -= 1
235 |
236 | # Calculate volume for each speaker
237 | left_volume = min(1, self.volume * volume)
238 | right_volume = left_volume
239 | if balance < 0:
240 | right_volume *= 1 - abs(balance)
241 | elif balance > 0:
242 | left_volume *= 1 - abs(balance)
243 |
244 | if self.max_play:
245 | for channel in self.rd["channels"]:
246 | if not channel.get_busy():
247 | channel.play(self.__sound, loops, maxtime, fade_time)
248 | channel.set_volume(left_volume, right_volume)
249 | break
250 | else:
251 | if force:
252 | channel = random.choice(self.rd["channels"])
253 | channel.play(self.__sound, loops, maxtime, fade_time)
254 | channel.set_volume(left_volume, right_volume)
255 | else:
256 | channel = _get_channel()
257 | channel.play(self.__sound, loops, maxtime, fade_time)
258 | channel.set_volume(left_volume, right_volume)
259 | self.__temp_channels.append(channel)
260 |
261 | # Clean up old temporary channels
262 | while (self.__temp_channels and
263 | not self.__temp_channels[0].get_busy()):
264 | _release_channel(self.__temp_channels.pop(0))
265 |
266 | def stop(self, fade_time=None):
267 | """
268 | Stop the sound.
269 |
270 | Parameters:
271 |
272 | - ``fade_time`` -- The time in milliseconds over which to fade
273 | the sound out before stopping; set to ``None`` or ``0`` to
274 | immediately stop the sound.
275 | """
276 | if self.__sound is not None and pygame.mixer.get_init():
277 | self.__sound.stop()
278 |
279 | def pause(self):
280 | """Pause playback of the sound."""
281 | for channel in self.rd["channels"]:
282 | channel.pause()
283 |
284 | def unpause(self):
285 | """Resume playback of the sound if paused."""
286 | for channel in self.rd["channels"]:
287 | channel.unpause()
288 |
289 |
290 | class Music:
291 |
292 | """
293 | This class stores and plays music. Music is very similar to sound
294 | effects, but only one music file can be played at a time and it is
295 | more efficient for larger files than :class:`sge.snd.Sound`.
296 |
297 | What music formats are supported depends on the implementation of
298 | the SGE, but Ogg Vorbis is generally a good choice. See the
299 | implementation-specific information for a full list of supported
300 | formats.
301 |
302 | .. attribute:: volume
303 |
304 | The volume of the music as a value from ``0`` to ``1`` (``0`` for
305 | no sound, ``1`` for maximum volume).
306 |
307 | .. attribute:: fname
308 |
309 | The file name of the music given when it was created.
310 | (Read-only)
311 |
312 | .. attribute:: length
313 |
314 | The length of the music in milliseconds. (Read-only)
315 |
316 | .. attribute:: playing
317 |
318 | Whether or not the music is playing. (Read-only)
319 |
320 | .. attribute:: position
321 |
322 | The current position (time) playback of the music is at in
323 | milliseconds. (Read-only)
324 |
325 | .. attribute:: rd
326 |
327 | Reserved dictionary for internal use by the SGE. (Read-only)
328 | """
329 |
330 | @property
331 | def volume(self):
332 | return self.__volume
333 |
334 | @volume.setter
335 | def volume(self, value):
336 | self.__volume = min(value, 1)
337 |
338 | if self.playing:
339 | pygame.mixer.music.set_volume(value)
340 |
341 | @property
342 | def length(self):
343 | if self.__length is None:
344 | if self.fname is not None:
345 | snd = pygame.mixer.Sound(self.fname)
346 | self.__length = snd.get_length() * 1000
347 | else:
348 | self.__length = 0
349 |
350 | return self.__length
351 |
352 | @property
353 | def playing(self):
354 | return r.music is self and pygame.mixer.music.get_busy()
355 |
356 | @property
357 | def position(self):
358 | if self.playing:
359 | return self.__start + pygame.mixer.music.get_pos()
360 | else:
361 | return 0
362 |
363 | def __init__(self, fname, volume=1):
364 | """
365 | Parameters:
366 |
367 | - ``fname`` -- The path to the sound file. If set to ``None``,
368 | this object will not actually play any music. If this is
369 | neither a valid sound file nor ``None``,
370 | :exc:`FileNotFoundError` is raised.
371 |
372 | All other arguments set the respective initial attributes of the
373 | music. See the documentation for :class:`sge.snd.Music` for
374 | more information.
375 | """
376 | self.rd = {}
377 | if fname is None or os.path.isfile(fname):
378 | self.fname = fname
379 | else:
380 | raise FileNotFoundError('File "{}" not found.'.format(fname))
381 | self.volume = volume
382 | self.rd["timeout"] = None
383 | self.rd["fade_time"] = None
384 | self.__start = 0
385 | self.__length = None
386 |
387 | def play(self, start=0, loops=1, maxtime=None, fade_time=None):
388 | """
389 | Play the music.
390 |
391 | Parameters:
392 |
393 | - ``start`` -- The number of milliseconds from the beginning to
394 | start playing at.
395 |
396 | See the documentation for :meth:`sge.snd.Sound.play` for more
397 | information.
398 | """
399 | if self.fname is None or not pygame.mixer.get_init():
400 | return
401 |
402 | if not self.playing:
403 | try:
404 | pygame.mixer.music.load(self.fname)
405 | except pygame.error as e:
406 | warnings.warn(str(e))
407 | return
408 |
409 | if not loops:
410 | loops = -1
411 |
412 | r.music = self
413 | self.rd["timeout"] = maxtime
414 | self.rd["fade_time"] = fade_time
415 |
416 | if fade_time is not None and fade_time > 0:
417 | pygame.mixer.music.set_volume(0)
418 | else:
419 | pygame.mixer.music.set_volume(self.volume)
420 |
421 | if self.fname.lower().endswith(".mod"):
422 | # MOD music is handled differently in Pygame: it uses
423 | # the pattern order number rather than the time to
424 | # indicate the start time.
425 | self._start = 0
426 | pygame.mixer.music.play(loops, start)
427 | else:
428 | self.__start = start
429 | try:
430 | pygame.mixer.music.play(loops, start / 1000)
431 | except NotImplementedError:
432 | pygame.mixer.music.play(loops)
433 |
434 | def queue(self, start=0, loops=1, maxtime=None, fade_time=None):
435 | """
436 | Queue the music for playback.
437 |
438 | This will cause the music to be added to a list of music to play
439 | in order, after the previous music has finished playing.
440 |
441 | See the documentation for :meth:`sge.snd.Music.play` for more
442 | information.
443 | """
444 | r.music_queue.append((self, start, loops, maxtime, fade_time))
445 |
446 | @staticmethod
447 | def stop(fade_time=None):
448 | """
449 | Stop the currently playing music.
450 |
451 | See the documentation for :meth:`sge.snd.Sound.stop` for more
452 | information.
453 | """
454 | if not pygame.mixer.get_init():
455 | return
456 |
457 | if fade_time:
458 | pygame.mixer.music.fadeout(fade_time)
459 | else:
460 | pygame.mixer.music.stop()
461 |
462 | # ``pygame.mixer.music.stop()`` should push
463 | # ``sge.MUSIC_END_EVENT``, which could cause a track to be
464 | # skipped in the music queue if we're starting a new one. so
465 | # if we have an empty queue, block that event.
466 | if not r.music_queue:
467 | block_event = pygame.event.Event(sge.MUSIC_END_BLOCK_EVENT)
468 | pygame.event.post(block_event)
469 |
470 | @staticmethod
471 | def pause():
472 | """Pause playback of the currently playing music."""
473 | pygame.mixer.music.pause()
474 |
475 | @staticmethod
476 | def unpause():
477 | """Resume playback of the currently playing music if paused."""
478 | pygame.mixer.music.unpause()
479 |
480 | @staticmethod
481 | def clear_queue():
482 | """Clear the music queue."""
483 | r.music_queue = []
484 |
485 | # Block any existing music end events that have been posted,
486 | # just in case a new music queue is started immediately after in
487 | # the same frame.
488 | if pygame.event.peek(sge.MUSIC_END_EVENT):
489 | block_event = pygame.event.Event(sge.MUSIC_END_BLOCK_EVENT)
490 | pygame.event.post(block_event)
491 |
492 |
493 | def stop_all():
494 | """Stop playback of all sounds."""
495 | pygame.mixer.stop()
496 |
--------------------------------------------------------------------------------