You can grab pre-release versions from PyPi. See the available versions from the Arcade PyPi Release History page.
- Fixed
DefaultTextureAtlasraisingKeyErrorwhen a texture was added while the garbage collector freed the last other texture with the same image and transform. The collector could run in the middle of adding the new texture, and the freed texture's finalizer removed the slot the new one was about to share. It showed up in CI on Python 3.14, whose garbage collector runs at different times, when loading a tile map. - Fixed blocky, uneven text on scaled (HiDPI) displays, such as Windows set to 125% or 150%. Arcade's windows use pyglet's
"stretch"scaling, so text was rasterized at the window's size and then stretched to fill the larger framebuffer, giving strokes of uneven width. It looked worse after the default font changed to Liberation Sans, which shows the stretching more than Calibri did.Text,draw_textand GUI text now lay their glyphs out at the framebuffer's resolution and draw them back at the same size, so they're sharp. Nothing changes at a scale of 100%.- Positions and sizes on
Text, such asx,content_widthandleft, are still in window units. The pyglet label inText.labeluses framebuffer pixels on a scaled display. - Text can come out a few percent wider, because the font is hinted for the larger size.
create_text_spriteis unchanged; its texture is the size of the text in window units.
- Positions and sizes on
- Fixed
DefaultTextureAtlaslosing track of textures that share an image, such as everySpriteSolidColorsize, which share one white image:- Once the first texture with a given image was freed while another was still in use, resizing the atlas, which happens when it fills up, raised
RuntimeError: Empty set in unique texturesand left the atlas half-resized. - If the last texture's finalizer ran before Python had cleared it from the atlas's records, the atlas kept the texture's name after freeing its slot. Adding another texture with that image then raised
Texture '...' not found in UVData. This showed up as an occasional CI failure.
- Once the first texture with a given image was freed while another was still in use, resizing the atlas, which happens when it fills up, raised
- Fixed
Sprite.remove_from_sprite_lists()raisingAttributeErrorfor a sprite registered withregister_physics_engine()on an engine without aremove_sprite()method, such asPhysicsEngineSimpleorPhysicsEnginePlatformer. It now only callsremove_sprite()on engines that have it. - Fixed a window sized with
arcade.get_display_size()being bigger than the screen with display scaling, such as Windows set to 125% or 150%. Arcade scales windows up by the display scale, butget_display_size()returned the screen's size in pixels, so the window was scaled up twice. It now returns the size in window units on Windows and Linux: at 125%, a 1920x1200 screen gives 1536x960, which fills it exactly. On macOS and the web it's unchanged, as they don't scale windows (#2791). - Fixed
arcade.future.background.ParallaxGroupraisingZeroDivisionErrorthe first time its offset changed after a layer was given a depth of 0. Setting a depth of 0 now raises aValueErrorright away, which says to usefloat("inf")for a layer that doesn't scroll (#1551). - GUI: Fixed a gap between
UIFlatButton's border and the edge of the button, half the border's width, which also showed onUIDropdown(#2868). - GUI: Passing a single style such as
UIFlatButton.UIStyle()as a widget'sstyleraised a confusingTypeErrorabout attribute names. It now raises aTypeErrorsaying a dict of styles for each state is needed, and how to start from the widget'sDEFAULT_STYLE(#2817). - GUI: Fixed
UITextArea:- With
document_mode="ATTRIBUTED"or"HTML", the widget's font and color replaced every style set in the text. Styles set in the text now win, and the widget's arguments apply to the rest. In HTML mode they also replace the decoder's own defaults, such as Times New Roman (#2441). boldanditalichad no effect, because pyglet 3 reads theweightandstylekeys instead.- The text widgets page of the
gui/2_widgetsexample now shows its labels in bold.
- With
- Fixed
arcade.math.rand_vec_spread_deg()returning vectors in random directions. It passed the angle in degrees to a function that expects radians, so for example the spread emitters in theparticle_systemsexample sprayed everywhere (#2648). - Fixed reading 2 GB or more from an OpenGL texture, texture array, framebuffer or buffer on Windows, which failed because
ctypes.string_attakes its size as a 32-bit C long there (#2836). - Fixed a player in
PhysicsEnginePlatformersliding along when standing across two moving platforms. It moved by both platforms' speeds added together, so it slid until it stood on only one. It now moves with the platform it stands on the most, and isn't moved by a platform it only touches the edge of while standing mostly on something still (#2782). - Fixed the PyInstaller hook bundling Arcade's version file at
arcade/VERSION/VERSION. Frozen apps printed an error on startup and reportedarcade.VERSIONas0.0.0, and builds usingcollect_all("arcade")failed because the hook andcollect_allput a folder and a file at the same path. The version file is nowarcade/_VERSION, so it can't be confused with thearcade.versionmodule (#2837). - Fixed drawing into a texture atlas losing new drawing when the atlas grows during
render_into(). Nested rendering and exception exits now restore the previous camera and render region. - Fixed several
arcade.create_text_sprite()bugs:- Sprites with the same text shared one image in the texture atlas, so creating a second one (for example in another color or size) changed the first one and drew the second stretched. Each sprite now gets its own image.
anchor_x="center"cut off the left half of the text, andanchor_x="right"made an empty sprite.- The sprite was placed too high. It now covers the same area as an
arcade.Textwith the same arguments at the same position. - An empty string raised
ValueError. It now makes a transparent sprite, as documented. - Text sprites went blank when the texture atlas rebuilt itself, which happens when it fills up after some textures were freed. The atlas redraws textures from their images, and a text sprite's image was empty.
sprite.texture.imagenow also contains the text. - Text sprites were drawn fainter than the same text drawn directly. Drawing the text into a transparent texture squared its alpha and multiplied its color by the alpha, so the sprite's alpha was applied twice: anti-aliased edges came out darker and thinner, text with partial alpha (for example
(255, 255, 255, 128)) was nearly invisible, and even with an opaquebackground_colorthe edges were partly transparent. The texture now has the text's own color and alpha.
- Fixed an
AttributeErrorbeing printed as "Exception ignored in__del__" when creating an OpenGL texture, framebuffer, buffer, program, compute shader, texture array, or vertex array failed, for example with an invalid number of texture components. - Fixed
arcade.draw_text()cache problems: a multiline call and an otherwise equal single-line call shared one label and drew wrong, and animatingrotationorfont_sizeadded a cached label every frame, forever. The cache now holds at most 256 labels, forgetting the least recently used. - Fixed
arcade.Textstyle properties:- Setting
italicafter creating the text had no visible effect."oblique"is now also accepted. boldstrings such as"light"or"semibold"were all treated as bold, including"normal". They now set that font weight, and theboldproperty returns the weight name for weights other than bold and normal.- A
pyglet.text.LinearGradientcolor raisedTypeErrorinText,draw_text(),create_text_sprite(), andUILabel.update_font(). Gradients now work, and thecolorproperty returns the gradient. - The
Textconstructor ignored every error while creating the label, so bad arguments such as an unknown keyword or an invalidfont_nameonly raised later, the first time the text was used. Only the "no window yet" case is deferred now.
- Setting
- Fixed
font_namepaths to font files inarcade.Text,draw_text(),create_text_sprite(), and theText.font_namesetter. A path or resource handle such as":resources:fonts/ttf/Custom.ttf"used the file name as the font name, so the text was drawn in the default font. The file is now loaded the first time it's used, and its family name is used. Lists of font names, which the docs allow, raisedTypeErrorand now work, and a path no longer takes priority over names listed before it. - Fixed drawing on scaled (HiDPI) displays, such as Windows set to 125% or 150%:
- After the first frame that drew text, the whole game was drawn too small, in the bottom left corner of the window. pyglet sets the window camera's viewport and scissor when it draws text, and Arcade gave them in window units instead of pixels, so they also stayed wrong for everything drawn after. Text was too small even in the first frame, and GUI text was drawn at the wrong size, outside its widget.
Window.get_pixel_ratio()returned pyglet's display scale instead of the framebuffer to window size ratio, which differ when pyglet'sdpi_scalingoption is"platform". Everything on screen was then drawn scaled up, cut off at the right and top.
- Fixed setting
Sprite.hit_box. The new hit box stayed at (0, 0) with a scale of 1 until the sprite moved or was scaled, so it collided with nothing, and a spatial hash didn't account for its size. It now takes the sprite's position, scale and angle right away. - Fixed fast sprites passing through thin walls and platforms in
PhysicsEngineSimpleandPhysicsEnginePlatformer. A sprite that moved farther than its own size plus the wall's thickness in one frame jumped over it, for example a player falling fast onto a thin platform. A move longer than the sprite is now checked in steps shorter than the sprite, so it stops at the first wall in the way. Moves shorter than the sprite work exactly as before. - Fixed collision checks with
CollisionMethod.GPU(also chosen automatically for lists of over 1500 sprites without a spatial hash) missing hit boxes that reach beyond a sprite's drawn size, such as a melee attack's reach. The GPU only knows the sprites' drawn sizes, so it now also uses the checking sprite's hit box, and eachSpriteListkeeps track of how far its sprites' hit boxes reach beyond their sizes. - Fixed drawing inside
TextureAtlas.render_into()when the atlas had to rebuild to make room, for example to add a new texture being drawn. A full atlas with freed space rebuilds instead of growing, which moved the texture being drawn into, so the drawing landed on other textures and what was drawn before was lost. While rendering into it, the atlas now grows instead if it can, and a rebuild keeps what was drawn and moves the drawing area with the texture. - Fixed a
SpriteListon WebGL only drawing its first 256 sprites when its storage was created with a capacity over 256: for exampleSpriteList(capacity=1000),clear()on a list that had grown past 256 sprites, or a lazy list with more than 256 sprites before it was first drawn (#2909). - Fixed platformer tutorial steps 7 to 19, the
custom_spriteexample, and the lights tutorial crashing on startup withAttributeError: property 'camera' ... has no setter. They stored their camera asself.cameraon the window, which is the default camera pyglet draws with. Their camera is nowself.world_camera, and assigningWindow.cameragives an error saying to use another name. - Fixed
arcade.gui.experimental.pixelated_ui()raisingAttributeError. It now turns off text anti-aliasing and makes font glyphs use nearest-neighbor filtering, as documented. - Fixed
InputManager.parse()raisingAttributeError, so a saved input configuration couldn't be loaded.
- Removed outdated and duplicate names from the
arcadenamespace (#2402):AnimatedWalkingSpriteand theFACE_UP,FACE_DOWN,FACE_LEFTandFACE_RIGHTconstants it used. Its docs already called it deprecated and said to write your own sprite class instead. Thesprite_move_animationexample shows how.get_game_controllers(), which did the same asget_joysticks(). Its name suggested it returned game controllers, but it returned joysticks. For game controllers, useget_controllers().draw_lrbt_rectangle_filledanddraw_lrbt_rectangle_outlinewere each listed twice inarcade.__all__.
- The default font is now Liberation Sans, which comes with Arcade, instead of whichever of Calibri and Arial the computer has (#1135). Text looks the same on every computer. It applies to
Text,draw_text(),create_text_sprite(),TextPool, and the GUI'sUILabel,UITextArea,UIInputTextand buttons (which still use Kenney Future first if you load the Kenney fonts). Liberation Sans has the same letter widths as Arial, so text on Windows, which used Calibri, is about 10% wider. For the old look, passfont_name=("calibri", "arial").- The Liberation fonts load the first time one is used, so
font_name="Liberation Mono"works withoutload_liberation_fonts(). UITextAreaandUIInputTextaccept font file paths and resource handles forfont_name, likeText.
- The Liberation fonts load the first time one is used, so
arcade.load_tilemap()andTileMapnow give every layer's sprite list a spatial hash by default (use_spatial_hash=True) (#2663). Forgetting it on a wall layer made collision checks against it much slower: 100 bullets checked against 2,000 wall tiles took 48 ms per frame without it and 0.6 ms with it. A hash makes moving a layer's sprites slower, so for a layer whose sprites move a lot, such as moving platforms, turn it off withlayer_options={"Moving Platforms": {"use_spatial_hash": False}}, or for the whole map withuse_spatial_hash=False.layer_optionsnow warns about option names it doesn't know, which it used to ignore. The performance tips page named the option"use_spatial_hashing"; it's"use_spatial_hash".
Sprite,BasicSprite,SpriteSolidColor,SpriteCircleandTextureAnimationSpriteraiseTypeErrorfor keyword arguments they don't accept, instead of silently ignoring them. For example,Sprite(path, hit_box_algorithm=...)used to do nothing; set the hit box algorithm when loading the texture instead.Spritenow takesvisibleas a named argument.SpriteSolidColor,SpriteCircleandTextureAnimationSpritenow pass extra keyword arguments on toSprite, so arguments such asangleandvisiblework. They used to be dropped.- This found arguments that had silently done nothing: tilemap image layers passed
filenameandhit_box_algorithm, animated tiles passedpath_or_texture, and platform tutorial steps 19 and 20 passedscalinginstead ofscale, so their bullets were drawn at full size instead of 80%.
arcade.math.get_angle_degrees()now measures clockwise from straight up, likeSprite.angle: 0 is up, 90 is right, 180 is down and -90 is left. It used to measure clockwise from the right, which disagreed withget_angle_radians(), which already measured from up (#2754). The two now always give the same angle in different units. A sprite whose image points up faces a point withsprite.angle = get_angle_degrees(...). For the old value, subtract 90.- Fixed the
sprite_rotate_around_tankexample's corrected barrel, which sat 90 degrees off from the mouse, and updatedturn_and_movefor the new angles.turn_and_move's sprite also now stops when moving straight along an axis, which it never did.
- Fixed the
- Added a keyword-only
decoderargument toarcade.Soundandarcade.load_sound, allowing a specific pygletMediaDecoderto load audio without subclassingSoundor registering the decoder globally (#2049). - Added
arcade.sweep_sprite(sprite, dx, dy, sprite_list), which checks the whole path of a moving sprite and returns aSweepInfofor the first sprite it would hit (thesprite, how far along the move as afractionanddistance, and the surfacenormal), orNone. Fast sprites can't pass through thin walls this way. A sprite that already overlaps one is an immediate hit. Added thesprite_bullets_sweepexample comparing it with a plain collision check. - Added the
sprite_pixel_demolitionexample, a stress test where every pixel of the Arcade logo is a sprite (28,000, or 71,000 with smaller pixels) and exploding bullets knock them loose as debris. Debris can move as Python sprites or on the GPU with a shader (press G), which keeps 60 FPS with 15,000 pieces in flight. - Added
arcade.sweep_line(start, end, sprite_list), which returns aSweepInfofor the first sprite a line hits (itsfraction,distance, and surfacenormal), orNone. It'ssweep_spritefor a point: for lasers, hitscan weapons, or seeing what's in the way. Added thesprite_laser_mirrorsexample, where a laser bounces off rotating mirrors using the normal.
- Ruff's pyupgrade rules are on for
arcadeandtests. Type annotations uselist,dict,X | Yandcollections.abcinstead of the deprecatedtypingaliases, mostly inarcade.gl(#2676). Nothing changes at runtime. - Sped up moving sprites in a
SpriteListwith a spatial hash (#1568). Moving, rotating or resizing a sprite used to remove it from the hash and add it again every time. Now it's only marked as moved, and the next collision check updates each moved sprite once, skipping any still in the same cells. Moving 5,000 hashed sprites withcenter_x += 1andcenter_y += 1went from 36 to 8 ms per frame, or from 39 to 22 ms with a collision check after. Collision checks with nothing moving cost the same.SpatialHash.contentsandbuckets_for_spriteare now properties that apply pending moves first. draw_lines,draw_points,draw_line_strip,draw_polygon_filledanddraw_polygon_outlineraise aValueErrornaming the first point that isn't 2 numbers, such aspoint_list[2] is 7, but each point must be 2 numbers, such as (x, y)(#2215). Before, a bad point raised a confusing error like'int' object is not iterable, and indraw_lines,draw_pointsanddraw_line_stripa point with 1 or 3 numbers silently shifted every number after it. The check costs one length comparison per call, and the points are now converted faster: drawing 1,000 lines or points went from about 137 to 90 µs per call.- The card game tutorial no longer passes
hit_box_algorithm="None"toSprite, an Arcade 2 argument thatSpritesilently ignores. Its text no longer says hit box calculation is slow: loading all 52 cards with their default hit boxes takes about 40 ms. - Removed the docs build's workaround for Sphinx not copying changed CSS files (
util/sphinx_static_file_temp_fix.pyand its.ENABLE_DEVMACHINE_SPHINX_STATIC_FIXswitch). Sphinx fixed it upstream, and the pinned Sphinx 9.1.0 copies changed CSS on incremental builds and withmake.py serve(#2266). - Docs fixes:
- The install guide, SBC guide and contributing guide said Arcade needs Python 3.9; it needs 3.10. The release checklist now lists everywhere the minimum version appears (#1302).
ShapeElementList's docstring links topyglet.shapes, and says "batch" where it said "back" (#2608).- The
gui/1_layoutsexample uses the bundled Liberation Sans instead of fonts most systems don't have (#2743). create_text_sprite()no longer warns that its sprite draws as a black box in a sprite list with a different texture atlas. That stopped being true in 4.0, when text sprites started keeping their image (#1883).
- Sped up
arcade.draw_text(). It no longer flushes OpenGL after every call (an unchanged call went from 76 to 15 µs), and several lines drawn in the same style each keep their own cached label instead of re-laying out one label every call (5 static lines went from 1.24 ms to 0.08 ms per frame). Any number of lines can share a style. A line whose text changes reuses its own label from the previous frame, found by the clock's tick count, instead of making a new one. - Sped up
arcade.Textupdates. Setting a property to the value it already has no longer lays out the text again (for examplefont_size,bold, orwidthwent from about 165 µs to under 1 µs), and awith text:block only lays out the text if something in it needs a new layout. An unchangedarcade.TextPoolframe with 5 lines went from 760 µs to 6 µs. - Added a "Drawing Text" page to the programming guide: choosing between
draw_text,Text,TextPool, andcreate_text_sprite, what's slow and fast to change, batches, fonts (names, font files, and the bundled Kenney and Liberation fonts), and styles. Updated the text section of the performance tips, and thedraw_textwarning and docstring, which overstated how slow it is. - Tile maps no longer use Pillow's
Image.getdata(), which is deprecated and will be removed in Pillow 14, to apply an image layer's transparent color. It's done with Pillow operations instead, which is also faster (a 1024x600 image went from 76 ms to 4 ms). - Sped up removing many sprites from a large
SpriteList, such as every bullet that hit something this frame.SpriteList.remove(), and soSprite.remove_from_sprite_lists()andkill(), used to search the whole list for each sprite. Removals now wait until the list is next used, and many are applied in one pass: removing 100 sprites from 41,000 went from 19 ms to 3.3 ms, and 500 from 166,000 went from 630 ms to 17 ms. Drawing order is kept, and a few removals cost the same as before. - Documented choosing a spatial hash cell size (
spatial_hash_cell_size) in the performance tips and theSpriteListdocs: about the size of the sprites in the list. With 4 pixel sprites, collision checks were 16 times faster with 8 pixel cells than with the default of 128. - Type checking with mypy and pyright now fails the CI check, like formatting and linting. Their existing errors are fixed.
- Fixed code excerpts in the docs that highlighted or showed the wrong lines, because the example code had changed since their line numbers were set. This covers 62 excerpts: 48 in the platformer, pymunk platformer, menu, card game, compute shader, raycasting and shader toy glow tutorials, and 14 on example pages. Most now highlight the same code they were written for. Where the code was rewritten, they highlight the code that does the same job now.
- Removed
arcade/experimental/perspective_parallax.py, an unreferenced demo ofPerspectiveProjectorthat didn't show a parallax effect. Thebackground_parallaxexample shows parallax scrolling. - Sped up
import arcadefrom about 2.7 to 0.9 seconds on Windows (#1159). Most of the time went to pyglet looking for game controllers when imported. Arcade now imports the controller code the first timeget_controllers(),ControllerManagerorget_joysticks()is used, so the wait happens then instead. Sound still loads at import, so playing the first sound doesn't pause the game.- Arcade's extra controller mappings now load at the same time. Code that calls
pyglet.input.get_controllers()directly without using Arcade's controller functions first only gets pyglet's own mappings.
- Arcade's extra controller mappings now load at the same time. Code that calls
- Updated pyglet to 3.0.dev11 (from 3.0.dev8). Arcade's library code needed no changes (only its docs build configuration did); these mostly affect code that uses pyglet directly.
pyglet.graphics.ShaderProgramnow requires avertex_layoutkeyword argument (apyglet.graphics.VertexLayout, orNoneto infer it from the shader).create_vertex_layout()andset_instance_attributes()are replaced byVertexLayoutandget_vertex_view(). Arcade's own shaders usearcade.gland are unaffected.- pyglet graphics resources (textures, buffers, shaders, framebuffers, ...) now have a backend
handleand a stablekey. The.idattribute is deprecated; use.handlefor backend calls and.keyfor equality and caching.MouseCursor.gl_drawablewas renamed toMouseCursor.api_drawable. pyglet.guiwas rewritten around a newUIManager. This doesn't affectarcade.gui.- Pressing Ctrl+C now stops
arcade.run()cleanly throughpyglet.app.exitinstead of raisingKeyboardInterrupt(except in headless mode, which uses its own loop). - On macOS 14 and later, pyglet can now drive window redraws from the display (
pyglet.options.osx_displaylink). Arcade schedules its own frames, so its update and draw rates are unaffected.
- Fixed
check_for_collision(and the list-based collision functions) missing collisions when a sprite was flipped with a negative scale. The negative width/height cancelled out in the broad-phase distance check, so flipped sprites could pass through each other. - Fixed
SpatialHashqueries (get_sprites_near_sprite,get_sprites_near_point,get_sprites_near_rect, and the collision functions that use them) adding an empty bucket for every grid cell they looked at. Memory use grew as sprites moved around large maps. Queries and adding sprites to a spatial hash are also faster, since the hit box points are now scanned once instead of four times. - Fixed
are_polygons_intersecting(and sprite collision checks) always returningFalsewhen a polygon had a repeated point, such as a closed polygon whose first point is repeated at the end. - Rotated hit boxes at right angles (90, 180, 270 degrees, etc.) now have exact point coordinates. Before, values like
sin(radians(180))being about 1.2e-16 instead of 0 left tiny errors that could make exactly touching sprites count as colliding, or not, differently from unrotated ones. - Fixed sprite collision checks missing collisions when a sprite's hit box is bigger than its texture, such as a custom hit box used as a melee reach area. The quick distance check estimated each sprite's size from its texture; it now uses the actual hit box, cached until the scale changes. This also makes the check tighter for most sprites, so brute-force list checks are about 20-40% faster.
- Fixed
Sprite.rescale_relative_to_point()(andSpriteList.rescale(), which uses it) not rescaling the sprite's hit box. The sprite was drawn at its new size but collided, and was placed in spatial hashes, at its old size. check_for_collision_with_listsno longer returns the same sprite more than once when it's in more than one of the lists.CollisionMethod.SPATIAL(method=1) on a sprite list without a spatial hash now chooses the same way asAUTO, checking every sprite in lists of 1500 or fewer. Before, it always used the GPU, which is slow when called many times per frame and needed an open window.- Documented that sprites whose hit boxes only touch don't count as colliding, while a point exactly on a hit box's edge does count for
get_sprites_at_pointandcollides_with_point. Correctedget_sprites_in_rect's docs, which said touching sprites were included. - Fixed
SpriteList.pop()with a negative index other than-1(such aspop(-2)) drawing the wrong sprites: the removed sprite stayed on screen and another sprite disappeared. - Fixed
SpriteList.rescale()moving the list's center while rescaling, so sprites after the first were scaled around the wrong point. - Fixed
SpriteList.preload_textures()raisingAttributeErroron a lazy sprite list that hadn't been drawn yet. It now preloads into the atlas the list will use. - Fixed GPU collision checks (
CollisionMethod.GPU, also used automatically for sprite lists over 1500 sprites without a spatial hash) missing sprites flipped with a negative scale, whose negative width or height made them look smaller than they are. - Fixed
SpriteList.__setitem__raising when setting a negative index to the sprite already there, such assprite_list[-1] = sprite_list[-1]. - Fixed
PhysicsEngineSimpleandPhysicsEnginePlatformerleaving a sprite overlapping a wall after it rotated against the wall while moving sideways. The sideways move was measured from where the sprite was before rotating, undoing the move out of the wall.
- Added
HitBox.get_adjusted_bounds(), which returns the cached(left, right, bottom, top)bounds of the adjusted hit box points. - Added
arcade.CollisionMethod, an enum for themethodargument ofcheck_for_collision_with_listandcheck_for_collision_with_lists:AUTO,SPATIAL,GPU, andSIMPLE. It's anIntEnum, so the numbers0to3still work. - Added
arcade.has_collision_with_list()andarcade.has_collision_with_lists(), which returnTrueas soon as they find a collision. They're faster than checking whethercheck_for_collision_with_list()returns an empty list, by about 18x when many sprites overlap. - Added
arcade.check_for_collision_between_lists(list_a, list_b), which returns every colliding(sprite_a, sprite_b)pair between two lists, such as bullets and enemies. Passing the same list twice returns each pair once. - Added
arcade.get_collision_info(sprite1, sprite2), which returns aCollisionInfowith the smallest move that separates two colliding sprites: a unitnormal(the direction to movesprite1) and adepthin pixels, orNoneif they don't collide. For example,player.position += info.normal * info.depthpushes a player out of a wall. Correct for convex hit boxes. - Added
arcade.get_collision_info_with_list(sprite, sprite_list), which returns a(sprite, CollisionInfo)pair for each sprite in the list thatspritecollides with, deepest overlap first. Added thesprite_push_outexample, which uses it to push a player out of walls, sliding along rotated ones.
PhysicsEngineSimpleandPhysicsEnginePlatformernow move sprites out of walls exactly, instead of in steps: landing on a floor or ramp and hitting a ceiling stop the sprite exactly at the surface (before, it could stop up to 0.25 px above a floor or 1 px below a ceiling), and rotating into a wall moves the sprite the smallest distance out of it (before, a whole number of pixels). The older searches are kept as a fallback, for example for concave hit boxes. Collisions are also faster: a hard landing went from about 230 to 42 µs, and a ceiling bump from about 104 to 36 µs.- Sped up several
SpriteListoperations:swap()no longer searches the draw order (about 1000x faster at the end of a 10,000 sprite list),insert()and item assignment check membership with a dictionary instead of scanning the list, and drawing uploads only the buffer slots in use instead of the whole capacity (moving one sprite and drawing is 1.6-2.3x faster). - The platformer and simple physics engines and
AStarBarrierListnow usehas_collision_with_list(s)where they only need to know whether there's a collision. Building anAStarBarrierListis about 7-9% faster. - Sped up sprite collision checks. Sprites that pass the quick distance check are now compared by cached hit box bounds before the polygon test, and the polygon test skips horizontal and vertical edges, which the bounds check already covers. Checks that reach the polygon test are about 2-4x faster, e.g. 8.0 to 2.3 µs for two box hit boxes and 21.6 to 10.2 µs for two default octagon hit boxes.
are_polygons_intersectingis also faster (7.3 to 1.6 µs for two rectangles). - Sped up collision checks further by caching each hit box's distinct edge directions. Parallel edges (such as opposite sides of the default octagon hit boxes, or matching edges on two sprites with the same angle) are only tested once, and the cache is kept when a sprite moves. Two unrotated octagon hit boxes go from 12.0 to 4.6 µs, and two rotated 30° from 20.8 to 6.9 µs.
SpatialHashnow uses the hit box's cached bounds to find a sprite's grid cells, so they're shared with collision checks. Adding, removing, and querying for sprites that haven't moved is about 33-40% faster.- Added collision benchmark scripts in
benchmarks/collisions/(micro.py,hit_box.py, andcompare_reference.py, which checks collision results against a simple reference on random sprite pairs) andbenchmarks/spatial_hash/queries.py. - Removed the unfinished
arcade.texture_atlas.atlas_arrayandatlas_bindlessmodules. They were empty placeholders marked "do not use", weren't exported, and had failed to import on Python 3.10-3.13 since 4.0's move off Python 3.9. - Updated the optional
pymunkextra to 7.3.0 (from 7.2.0). Packaging-only release (free-threaded CPython and pyodide wheels, improved type hints) with no breaking changes or deprecations.
- Updated pyglet to 3.0.dev8 (from 3.0.dev7).
dev8adds aWindow.camerasetter (assign anyBaseCamerato change the window's default draw camera). Arcade'sWindow.camera/default_cameraremain read-only aliases for Arcade's ownDefaultProjectorand are unaffected by this change.dev8adds built-in text effects:pyglet.text.Stroke,pyglet.text.DropShadow, andpyglet.text.LinearGradient, usable viastroke/shadow/coloronpyglet.text.Label.arcade.Textpassesstroke=/shadow=through to pyglet already, butcolor=LinearGradient(...)currently raises insidearcade.Text/Color.from_iterable, which assumes a plain RGBA tuple — Arcade does not yet support gradient fills. Advanced users who want a gradient fill today can create apyglet.text.Labeldirectly instead ofarcade.Text.
- GUI: Added an experimental animation API in
arcade.gui.experimental—UIAnimatedGroupwraps a widget subtree and tweens its transform properties over time viaanimate().UIAnimatedGroupcaches its subtree into a surface and exposes non-layouting transform properties (scale,angle,alpha,offset_x,offset_y,tint); it is interactive, hit-testinghovered/pressed/on_clickagainst its untransformed rect.UIRenderGroupis the non-interactive caching primitive.animate()supports multiple properties per call, sequencing viathen(), repetition (repeat,yoyo), relative targets (rel()), easing, delays andon_finishcallbacks.- Animations are resolved per property: starting a new animation takes over its properties from running ones, other properties keep animating.
- Interpolates numbers, tuples,
Colorand vector types; non-interpolatable values snap at the end. - The low level
Transition*classes remain available for custom behavior.
- GUI: Fixed
UILabel.update_fontalways reporting a font change when the requested font was a fallback tuple (e.g.UIFlatButton's default styles), which caused a full UI re-render every frame. This made widget-heavy UIs, such as theexp_scroll_areaexample, run at a few FPS. - Fixed
rotate_around_pointmissing fromarcade.math.__all__, which made it unavailable viafrom arcade.math import *.
- Updated pyglet to 3.0.dev7 (from 3.0.dev3).
- Between
dev4anddev5, pyglet removedwindow._matricesand moved window view/projection/viewport onto its own camera (default_camerain dev5/dev6, renamed tocamerain dev7), backed by a per-frame ring-buffer UBO. Arcade now fully owns its own window matrix UBO, independent of pyglet's camera/ring buffer, so rendering behavior for cameras, sprites, and shapes is unchanged. - Advanced users who mix raw pyglet camera/window code with Arcade should note:
window._matricesno longer exists, andwindow.camera(pyglet'sdefault_cameraprior to dev7) is pyglet's own concept (aCamera2D), distinct fromarcade.Window.default_camera(Arcade's ownDefaultProjector) — both exist simultaneously and serve different roles.arcade.Windownow also exposes acameraproperty as an alias fordefault_camera, matching pyglet's dev7 rename. - Fixed
BackgroundTexturescale and offset producing incorrect visual transforms — Arcade's code was inadvertently relying on bugs in pyglet's pre-dev7Mat3.scale/Mat3.translatethat have since been fixed upstream. Visual output forBackgroundTextureusers with non-defaultscale/offsetvalues will change to be correct.
- Between
- Resolved security vulnerabilities in the
setuptools,click, andtyperdependencies (typerbumped to 0.27.1) viauv audit/uv lock.
- GUI: Added
UIInteractiveSpriteWidget— combinesUIInteractiveWidgetandUISpriteWidgetto make sprites clickable and hoverable in the UI tree. See #2847- Supports
hovered,pressed, anddisabledstates withon_clickevent dispatch. - Widget size defaults to the sprite's texture dimensions, overridable with explicit
width/height.
- Supports
- Added
TextPool- provides a mechanism for caching Text objects for re-use
- Fixed an issue where pixel scaling for high-dpi displays did not work correctly in web browsers via Pyodide. See #2846
- Fixed issues with update/draw rate handling that changes with Pyglet 3, rates are now handled properly between desktop and browser. See #2845
- Fixed caret behavior not responding appropriately when activating an input field. See #2850
- Added
pixel_perfectoption for 1:1 pixel ratio rendering, ignoring OS DPI scaling. See #2841 - Added
apply_torqueandset_angular_velocitywrappers for the Pymunk physics engine. See #2838 - Added file drop support in application window via
file_dropsparameter. See #2825 - New hexagon utilities module. See #2695
- New CLI infrastructure. See #2828
- GUI:
UIDropdownnow supports scrolling when options exceed the menu height. New parameters:max_height,invert_scroll,scroll_speed, andshow_scroll_bar. See #2833 - GUI: Warning when layout width/height is given but size_hint will override it. See #2834
- Fixed angle negation for Pymunk physics engine to ensure correct sprite rotation. See #2840
- Updated pyglet to 3.0.dev3. See #2842
- Tilemap: Sprites of an object tile layer will now apply visibility of the object. See #2829
- Split doc dependencies into separate group and upgraded Sphinx to 9.1.0. See #2843
- Added note about including
arcade.experimentalwhen compiling with Nuitka. See #2831
- Removes an unnecessary dependency on NumPy which caused breakage in web browsers.
- Fixes to camera module handling framebuffer changes. See 2802
- Small fixes to new easing functions. See 2810
- Updated pyglet to 3.0.dev2
- Small changes to the new input package between 4.0.0.dev1 and dev2. Namely
ControllerAxesrenamed/split toControllerSticksandControllerTriggers. There are more underlying changes which shouldn't impact the public API of InputManager.
- Support for running with Pyodide in web browsers.
- New
animmodule. Currently contains new easing/lerp utilities.
arcade.easinghas been removed, and replaced by the newarcade.anim.easingmodule.arcade.future.inputpackage has been moved to the top levelarcade.input.
UIManagerdid not apply size hint of (0,0). Mainly an issue withUIBoxLayout.- Allow multiple children in
UIScrollArea. - Fix
UIDropdown Overlaypositioning within aUIScrollArea.
- Upgraded Pillow to 12.0.0 for Python 3.14 support.
- Adds a new
arcade.NoAracdeWindowErrorexception type. This is raised when certain window operations are performed and there is no valid Arcade window found. Previously where this error would be raised, we raised a standardRuntimeError, this made it harder to properly catch and act accordingly. This new exception subclassesRuntimeError, so you can still catch this error the same way as before. Thearcade.get_window()function will now raise this if there is no window. - Along with the new exception type, is a new
arcade.windows_exists()function which will return True or False based on if there is currently an active window.
-
Support for Python 3.14
-
Fixes a bug with the
check_for_collision_with_listsfunction. This function is intended to mimic the functionality ofcheck_for_collision_with_listbut allow passing multiple lists and looping the same behavior. Thelistsfunction however handled the collision method differently. Which resulted in only spatial hash being used if it was available, or GPU collision. It would never fallback to the pure CPU brute force approach, which is the best option for spritelists which don't have spatial hash and less than 1,500 sprites. Certain games may see a substantial performance improvement from this change. See 2762 -
Added
center_xandcenter_yarguments toarcade.SpriteCircle. See 2766 -
Added a
rectproperty toarcade.Textobjects which will return anarcade.Rectbased on theleft,right,bottom, andtopvalues of the Text object. See 2759 -
Camera
- Fixes the position flag in
Camera2D.match_windowto so (0, 0) as the bottom left, instead of matching the center. See 2646
- Fixes the position flag in
-
PyInstaller
- Fixed an issue where imports for backends for the
arcade.glpackage could not be discovered by PyInstaller. Since 3.3.0 users have needed to add these hidden imports via the pyinstaller CLI in order for Arcade to work. See 2764
- Fixed an issue where imports for backends for the
-
GUI
- Fix a bug, where the caret of UIInputText was misplaced after resizing the widget
- Use incremental layout for UIScrollArea to improve performance of changing text
- Refactored and improved focus handling
- UIBoxLayout ignores widgets with
visible=None
- GUI
- Fix UIScrollBar creation
- Fix memory leak: widgets were not garbage collected
- Fixed an issue causing NinePatch to not render correctly
- TextureAtlas now as a
versionattribute that is incremented when the atlas is resized or rebuilt. This way it's easy to track when texture coordinates has changed. - Added
Text.visible(bool) property to control the visibility of text objects. - Fixed an issue causing points and lines to draw random primitives when passing in an empty list.
- GUI
- Fix caret did not deactivate because of consumed mouse events. 2725
- Property listener can now receive:
- no args
- instance
- instance, value
- instance, value, old value
Listener accepting
*argsreceiveinstance, valuelike in previous versions.
-
Fixed an issue causing a crash when closing the window
-
Added
Window.closed(bool) attribute indicating if the window is closed -
Fixed an issue where
on_drawcould be dispatched after the window was closed -
Added
PymunkPhysicsEngine.update_spritefor manually updating a sprite's shape to synchronize sprite hit boxes with the physics engine -
Fixed an issue causing
on_mouse_leaveto be called from disabledSections -
Various documentation fixes and improvements
-
Scene
Scene.add_spritenow returns the added spriteScene.add_sprite_listnow returns the added sprite listScene.add_sprite_beforenow returns the added sprite listScene.move_sprite_list_beforenow returns the moved sprite listScene.remove_sprite_list_by_indexnow returns the removed sprite listScene.remove_sprite_list_by_namenow returns the removed sprite list
-
GUI
- Fix
UILabelwith enabled multiline sometimes cut off text - Improved
UIWidgetusability for resizing and positioning:- Added property setters for
width,height, andsizethat ensure positive values - Added property setters for
center_xandcenter_y - Added property setters for
left,right,top, andbottom - Users can now set widget position and size more intuitively without needing to access the
rectproperty
- Added property setters for
- Fix
-
Rendering:
- The
arcade.glpackage was restructured to be more modular in preparation for other backends such as WebGL and WebGPU - Rewrote many shader programs to not use geometry shaders, which are not supported in WebGL and some other rendering backends
- Fixed a few instances og exceptions not being raised properly in edge cases
- BREAKING CHANGE:
SpriteListnow has multiple rendering systems supporting both WebGL and Desktop GL. If you have customized spritelist rendering you now need to modify theSpriteListDatainstance on the spritelist accessed throughSpriteList.data. This instance holds all the GPU-related resources for the spritelist such as buffers, textures, geometry and shader program.
- The
- GUI
- Fix
UIScrollArea.addalways returning None - Support
layerinUIView.add_widget() - Fix a bug which caused
UIScrollAreato refresh on every frame - Add stepping to
UISlider(thanks csd4ni3l) - Experimental controller support (incl. documentation)
- Fix
- Text objects are now lazy and can be created before the window
- Introduce
arcade.SpriteSequence[T]as a covariant supertype ofarcade.SpriteList[T](this is similar to Python'sSequence[T], which is a supertype oflist[T]) and various improvements to the typing of the API that leverage it - Fixed a nasty memory leak in texture atlases. This only affects projects managing their own atlases
- Fixed a bug causing some events to not trigger on the window's keyboard and mouse state handlers
- New minimum pyglet version is now 2.1.5
- Some shaders programs were rewritten to not use geometry shaders in preparation for webgl support
- Drop Python 3.9 support
- Disable shadow window on all platforms to provide a consistent experience
- Performance
- Improved performance of
arcade.SpriteList.remove()~300% - Improved
arcade.SpriteList.pop()performance making itO(1)instead ofO(N) - Improved performance of
arcade.hitbox.Hitbox.get_adjusted_points()~35% - Improved performance of
arcade.SpriteList.draw_hit_boxes()~20x
- Improved performance of
- GUI
arcade.gui.widgets.text.UIInputText- now supports styles for
normal,disabled,hovered,pressedandinvalidstates - provides a
invalidproperty to indicate if the input is invalid
- now supports styles for
- Added experimental
arcade.gui.experimental.UIRestrictedInputa subclass ofUIInputTextthat restricts the input to a specific set of characters arcade.gui.NinePatchTextureis now lazy and can be created before a window exists allowing creation during imports.- Improve
arcade.gui.experimental.scroll_area.ScrollBarbehavior to match HTML scrollbars
- Support drawing hitboxes using RBG or RGBA
- Fixed a bug causing some events to not trigger on the window's keyboard and mouse state handlers
- Many documenation fixes and improvements
- Various example fixes
UIWidget.with_backgroundnow accepts a tuple for color- Many docstring and documentation fixes
- Major fix for smooth frame rates. Due to a weakness with how certain
events are handled in the pyglet clock we now trigger
on_update,on_draw, andon_fixed_updatefrom a single event in pyglet and dispatch the events manually in Arcade. This should greatly improve the smoothness of scrolling and animations. A new limitation is that the draw rate cannot be faster than the update rate. - Fixed division error in box layout algorithm
- Fix example added buttons to multiple layouts
- Fixed blurriness in
UIWidgettext during interaction - Resolved issue with
UIDropdown.hide()when no parent exists - Corrected event order bug in
UIWidget - Clarify error message when the texture atlas is full. The default texture atlas has a limit of 8192 textures. This can be increased by the user if needed or the user can create multiple texture atlases.
- Many docstring and documentation fixes
- Added style support for
UIDropboxbuttons
Version 3.0.0 is a major update to Arcade. It breaks compatibility with the 2.6 API.
These are the breaking API changes. Use this as a quick reference for updating 2.6 code. You can find more details in later sections. Lots of behavior has changed even if the interface hasn't. If you are porting old code, read through these logs thoroughly.
-
Dropped Python 3.8 support completely.
-
Texture management has completely changed in 3.0. In the past, we cached everything, which caused issues for larger projects that needed memory management. Functions like
Arcade.load_textureno longer cache textures. -
Removed the poorly named
Window.set_viewportandset_viewportmethods.Camera2Dhas completely superseded their functionality. -
Fixed
ArcadeContextassuming that the projection and view matrices were aligned to the xy-plane and Orthographic. It is now safe to use full 3D matrices with Arcade. -
The
Spriteinitializer has been simplified. It's no longer possible to slice or transform textures through parameters in the sprite initializer. Use theTextureclass to manipulate the sprite's texture. It supports transforms like rotating, scaling, flipping, and slicing. -
Sprite.anglehas changed to clockwise. -
Sprite.on_updatehas been removed. UseSprite.updateinstead. It has adelta_timeparameter and accepts both*argsand**kwargsto support custom parameters. The same applies toSpriteList. -
Sprite.drawhas been removed. Use eitherarcade.draw.draw_spriteor anarcade.SpriteList. -
Removed
Sprite.face_pointandSprite.collision_radius. -
The deprecated
update()function has been removed from thearcade.Window,arcade.View,arcade.Section, andarcade.SectionManagerclasses. Instead, please use thearcade.Window.on_update()function. It works the same as theupdatefunction but has a "delta_time" parameter, which holds the time in seconds since the last update. -
The
update_rateparameter ofarcade.Windowcan no longer be set toNone. It previously defaulted to1 / 60but could be set toNone. The default is still the same, but setting it to None will not do anything. -
Sprites created from the
~arcade.tilemap.TileMapclass would previously set a key in theSprite.propertiesdictionary namedtype. This key has been renamed to "class " in keeping with Tiled renaming the key. -
The
arcade.text_pillowandarcade.text_pygletmodules have been completely removed. The Pillow implementation is gone, and the Pyglet version has been renamedarcade.text. -
Due to the above change.
arcade.create_text_spritehas been reworked to use the Pyglet-based text system. It has no API-breaking changes, but the underlying functionality has changed drastically. It may be worth rechecking the docs if you use this function. The main concern is if you are using a customarcade.TextureAtlas. -
Buffered shapes (shape list items) have been moved to their sub-module.
-
The
use_spatial_hashparameter forSpriteListandTileMapis now aboolinstead ofOptional[bool] -
arcade.draw_text()andarcade.text.Textarguments have changed.xandyhave replacedstart_xandstart_y.alignno longer interferes withmultiline. -
Moved or removed items from
arcade.util:- Removed:
arcade.util.generate_uuid_from_kwargsarcade.util._Vec2:- This was an internal class as indicated by the
_prefix - It was an old version of pyglet's
pyglet.math.Vec2 - Arcade code now uses
pyglet.math.Vec2directly
- This was an internal class as indicated by the
- Moved to
arcade.math:arcade.util.rand_in_circleis now:- located at
arcade.math.rand_in_circle - better at returning an even distribution of points PR2426 (remove any
math.sqrtwrapping it)
- located at
arcade.util.rand_on_circleis nowarcade.math.rand_on_circlearcade.util.lerpis now:- located at
arcade.math.lerp - compatible with any type which implements numerical
+,-, and*operators- NOTE: lerping vectors may be more efficient when using dedicated functions and methods:
- When lerping
pylget.math.Vec2, use one of:pyglet.math.Vec2's built inlerpmethodarcade.math.lerp_2dfor generaltuplecompatibility
- When lerping
pylget.math.Vec3, use one of:pyglet.math.Vec3's built inlerpmethodarcade.math.lerp_2dfor generaltuplecompatibility
- When lerping
- NOTE: lerping vectors may be more efficient when using dedicated functions and methods:
- located at
arcade.util.lerp_vecis nowarcade.math.lerp_2darcade.util.rand_in_rectis nowarcade.math.rand_in_rectarcade.util.rand_on_lineis nowarcade.math.rand_on_linearcade.util.rand_angle_360_degis nowarcade.math.rand_angle_360_degarcade.util.rand_angle_spread_degis nowarcade.math.rand_angle_spread_degarcade.util.rand_spread_degis nowarcade.math.rand_spread_degarcade.util.rand_magnitudeis nowarcade.math.rand_magnitude
- Removed:
-
GUI
- Removed
arcade.gui.widgets.UIWrapper. It is now a part ofarcade.gui.widgets.UILayout. - Removed
arcade.gui.widgets.UIBorder. It is now a part ofarcade.gui.widgets.UIWidget. - Removed
arcade.gui.widgets.UIPadding. It is now a part ofarcade.gui.widgets.UIWidget. - Removed
arcade.gui.widgets.UITexturePane. It is now a part ofarcade.gui.widgets.UIWidget. - Removed
arcade.gui.widgets.UIAnchorWidgethas been replaced byarcade.gui.widgets.UIAnchorLayout.
- Removed
-
Resources
- Removed unused resources from
resources/gui_basic_assets.items/shield_gold.pngitems/sword_gold.pngslider_thumb.pngslider_track.pngtoggle/switch_green.pngtoggle/switch_red.png
- Removed unused resources from
-
The texture atlas has been heavily reworked to be more efficient.
-
Alpha blending (handling of transparency) is no longer globally enabled but instead enabled when needed. draw functions and objects like
SpriteListandShapeElementListhave new arguments to toggle blending states. Blending states are now reset after drawing. -
Arcade now supports OpenGL ES 3.1/3.2 and has been tested on the Raspberry Pi 4 and 5. Any model using the Cortex-A72 or Cortex-A76 CPU should work. Use images from 2024 or later for best results.
-
Arcade now supports freely mixing Pyglet and Arcade code. You can now freely use Pyglet batches and Labels when preferred over Arcade's types. Note that texture/image handling is still a separate system.
-
A fully functioning 2D camera allows for moving, rotating, and zooming and works with Arcade and Pyglet.
-
Added a new
GLOBAL_CLOCKandGLOBAL_FIXED_CLOCKaccessable fromarcade.clock. which provides global access to elapsed time, number of frames, and the last delta_time.
- Removed the
updatefunction in favor ofarcade.Window.on_update(). - The
update_rateparameter in the constructor can no longer be set toNoneand must be a float. - A new
draw_rateparameter inarcade.Window.__init__, controls the call interval ofarcade.Window.on_draw(). It is now possible to separate the draw and update speeds of Arcade windows. Keepingdraw_rateclose to the refresh rate of the user's monitor while settingupdate_rate` to a much shorter interval can greatly improve the perceived smoothness of your application. open_window()now accepts**kwargsto pass additional parameters to thearcade.Windowconstructor.arcade.View- Removal of the
updatefunction in favor ofarcade.View.on_update().
- Removal of the
arcade.Sectionandarcade.SectionManager- Removal of the
updatefunction in favor ofarcade.Section.on_update().
- Removal of the
- Added a whole new
on_fixed_updatemethod, which is called with a regular delta time- Is also available for
arcade. View. - Control the rate of fixed updates with the
fixed_rate. parameter inWindow.__init__. - Control the max number of fixed updates per regular update with the
fixed_rate_capparameter inWindow.__init__.
- Is also available for
- See the updated event loop docs for an in-depth explanation of
on_fixed_updatevs.on_update.
- Created
arcade.camera.Camera2D, which allows for easy manipulation of Arcade and Pyglet's rendering matrices. - Created
arcade.camera.PerspectiveProjectorandarcade.camera.OrthographicProjector. Which can manipulate the matrices in 3D space. - Created methods to rotate and move cameras.
- Created methods to generate view and projection matrices needed by projector objects.
- Created static projector classes to set the matrices with constant values.
- Added a default camera that automatically adjusts to the active render target.
- Added a camera shake object that makes adding a camera shake to a game easy.
- All
Projectorclasses provide methods to project to and from the screen and world coordinates.
arcade.load_texturehas been simplified to load the entire image. Usearcade.load_spritesheetto use better versions of the old arguments.arcade.get_default_textureandarcade.get_default_imageare new methods to givearcade.Spritetheir default texture.- Added
sync_texture_imageto theDefaultTextureAtlasmethod to sync the texture in the atlas back into the internal pillow image in thearcade.Texture. - DefaultTextureAtlas: Added
get_texture_imagemethod to get pixel data of a texture in the atlas as a pillow image.
-
arcade.gui.widgets.UIWidget- Supports padding, border, and background (color or texture).
- Visibility: visible=False will prevent widget rendering. It will also not receive any UI events.
- Dropped
arcade.gui.widget.UIWidget.with_space_around. UIWidget.with_methods no longer wrap the widget. They only change the attributes.- Fixed a blending issue when rendering the GUI surface to the screen.
- Now supports nine-patch background textures.
- General performance improvements.
- Some attributes were removed from the public interface; use
UIWidget.with_methods instead.UIWidget.border_widthUIWidget.border_colorUIWidget.bg_colorUIWidget.bg_textureUIWidget.padding_topUIWidget.padding_rightUIWidget.padding_bottomUIWidget.padding_left
- Update and add example code.
- Iterable (providing direct children)
-
Updated widgets
arcade.gui.widgets.text.UIInputTextemits anon_changeevent.arcade.gui.widgets.slider.UITextureSlidertexture names changed to fit the naming pattern.
-
New widgets:
arcade.gui.widgets.dropdown.UIDropdownarcade.gui.widgets.image.UIImagearcade.gui.widgets.slider.UISliderarcade.gui.widgets.constructs.UIButtonRow(PR1580)
-
arcade.gui.UIInteractiveWidgetonly reacts to left mouse button events. -
Arcade
arcade.gui.property.Property:- Properties are observable attributes (supports primitive, list, and dict). A Listener can be bound with
arcade.gui.property.bind.
- Properties are observable attributes (supports primitive, list, and dict). A Listener can be bound with
-
All
arcade.gui.UILayouts now supportsize_hint,size_hint_min, andsize_hint_max.arcade.gui.UIBoxLayoutarcade.gui.UIAnchorLayoutArcade.gui.UIGridLayoutPR1478
-
Added color-consistent assets to
arcade.resources.gui_basic_assets. -
Provide GUI-friendly color constants in
arcade.uicolor. -
Replace deprecated usage of
arcade.draw_text.
- Added a
Recttype, making working with axis-aligned rectangles easy.- Provides functions to create a full
Rectobject from four values. - Provides methods to move and scale the
Rect. - Provides methods to compare against the
Rectwith 2D points and otherRects.
- Provides functions to create a full
- Added
AnchorPointhelpers and aliases forVec2s in the range (0 - 1). - Added several helper methods for creating
Rectobjects.LRBT(left, right, bottom, top)LBWH(left, bottom, width, height)XYWH(x, y, width, height, anchor = AnchorPoint.CENTER)XYRR(center_x, center_y, half_width, half_height)(this is mostly used for GL.)Viewport(left, bottom, width, height)(where all inputs areints.)
- Several properties in the library now return a
Rect:Window.rectBasicSprite.rectOrthographicProjectionData.rectUIWidget.rectSection.rect
- The drawing functions
draw_rect_filled()anddraw_rect_outline()can be used to draw aRectdirectly.
arcade.experimentalhas been split into two submodules,experimentalandfuture.futureincludes all incomplete features we intend to include in Arcade eventuallyexperimentalis any interesting code that may not end up as Arcade features.
arcade.color_from_hex_stringchanged to follow the CSS hex string standard.- Made Pyglet's math classes accessible within Arcade.
- Arcade's utility math functions have more robust typing.
- Added
Point,Point2,Point3type aliases for tuples and vectors. - Added
Sequencetypes for all threePointaliases. - Added a
Colorobject with a plethora of useful methods. - Windows Text glyphs are now created with DirectWrite instead of GDI.
- Removal of various deprecated functions and parameters.
- OpenGL matrix uniforms are now supported properly
- OpenGL uniforms now accept buffer protocol objects
- Sprite's visible flag is now handled correctly
Window.run()now supports a view argument.- OpenGL examples moved to
examples/gl <https://github.com/pythonarcade/arcade/tree/development/arcade/examples/gl>from "experiments/examples"
- Created
BasicSprite, the absolute minimum required for an Arcade sprite most users will do well sticking withSprite. Sprite.drawhas been completely removed. It was a wasteful and slow way to render a sprite. Use anarcade.SpriteListorarcade.draw.draw_sprite.Sprite.visibleno longer overrides the sprite's alpha, allowing for toggling transparent sprites.Sprite.face_towardshas been removed as it did not behave as expected and is not strictly for sprites.Sprite.collision_radiushas been removed as it is no longer used in collision checking. Sprites now only rely on their hitbox.- The
arcade.Sprite.__init__has been changed to remove all references to texture loading. Usearcade.load_textureandarcade.load_spritesheetfor more complex behavior. arcade.Sprite.anglenow rotates clockwise following standard game behavior. It may break common linear algebra methods, but reversing the resulting angles is easy.
Previously, controllers were usable via the Arcade.joysticks module. This module is still available in 3.0.
However, most people can treat it as depreciated. It is an alias to Pyglet's joysticks sub-module. There is now an arcade.controller module that is an alias to Pyglet's new Controller API. This change should make a more comprehensive choice of controllers usable with Arcade. The joystick module may still be helpful if you need specialty controllers such as racing wheels or flight sticks. The example code now uses the new controller AP.
- Complete removal of the old PIL-based text system. In 2.6, we switched to the newer Pyglet-based system, but there were still remnants of the PIL implementation—namely, the
arcade.create_text_spritefunction. There's no API breaking change, but if you are using the function, it would be worth reading the new docs, as there are some different considerations when using a customarcade.TextureAtlas. This function is faster than the old PIL implementation. Texture generation happens almost entirely on the GPU now. - The
arcade.text_pillowmodule no longer exists. arcade.text_pyglethas been renamedarcade.text.arcade.draw_textandarcade.Textnow accept azparameter that defaults to 0. Previous text versions had the same default.
arcade.draw_commandshas been renamedarcade.draw.- Added
arcade.draw.draw_lbwh_rectangle_texturedwhich replaces the now-deprecatedarcade.draw_commands.draw_lrwh_rectangle_textured. Usage has stayed the same as it was misnamed.
- Support for OpenGL ES 3.1 and 3.2. 3.2 is fully supported, and 3.1 is only supported if the driver provides the
EXT_geometry_shaderextension. It is part of the minimum spec in 3.2, so it is guaranteed to be there. Arcade only needs this extension to function with 3.1. - For example, the Raspberry Pi 4/5 only supports OpenGL ES 3.1 but provides the extension, making it fully compatible with Arcade.
- Textures now support immutable storage for OpenGL ES compatibility.
- Arcade is now using Pyglet's projection and view matrix.
All functions setting matrices will update the Pyglet window's
viewandprojectionattributes. Arcade shaders are also using Pyglet'sWindowBlockUBO. - Uniforms are now set using
glProgramUniforminstead ofglUniformwhen the extension is available, improving performance. - Fixed many implicit type conversions in the shader code for broader support.
- Added
front_faceproperty on the context for configuring the winding order of triangles. - Added
cull_faceproperty to the context to configure what triangle faces to cull. - Added support for bindless textures.
- Added support for 64-bit integer uniforms.
- Added support for 64-bit float uniforms.
- Now supports tiles defined as a sub-rectangle of an image. See Tiled 1.9 Release Notes for more information on this feature.
- Changed the
Sprite.propertieskey "type" to "class" to stay in line with Tiled's API. - You can now define a custom texture atlas for SpriteLists created in a TileMap. You can provide a default with the
texture_atlasparameter of thearcade.tilemap.Tilemapandarcade.tilemap.load_tilemap. The newtexture_atlaskey of thelayer_optionsdict lets you control it per layer. The globalTextureAtlaswill be used by default (This is how it works pre-Arcade 3.0). - Fixed animated tiles from sprite sheets.
- Collision detection is now even faster.
- Remove Shapely for collision detection, as Python 3.11+ is faster without it.
- New buffered
Arcade.create_triangles_strip_filled_with_colors. arcade.shape_listnow contains all items that can rendered using anarcade.ShapeElementList.
- Example code page has been reorganized.
- CONTRIBUTING.md has been updated.
- Improved
background_parallaxexample. - More detailed information on how Arcade's event loop works.
- The platformer tutorial has been overhauled.
- These features are all in active development, and their API can change anytime. Feedback is always appreciated.
- Started on a system for drawing large background textures with parallax scrolling. These don't use an
arcade.TextureAtlasso they aren't batched, preventing your Atlas' from being filled with massive images. - Started on an event-based input system, which includes improved Enums for key, mouse, and controller inputs. Using the InputManager, you can define custom actions that can rebound at run time and have multiple valid keys.
- Added a method to bootstrap
arcade.clock.Clock, adding functionality to add sub-clocks that their parent will tick. This makes it much safer to manipulate the time of particular game objects. - A new subclass of
arcade.BasicSpritethat usedpyglet.math.Vec2for most of its properties. It has a heavy performance hit but is much nicer to work with. - The experimental lighting features have been promoted to the future, but their implementation is very volatile. If you have ideas for what you'd like from a lighting module, please share them on Discord.
Contributing to a release comes in many forms. It can be code, documentation, testing, or providing feedback. It's hard to keep track of all the people involved in a release, but we want to thank everyone who has helped in any shape or form. We appreciate all of you!
- Andrew Bradley
- Alejandro Casanovas
- Cleptomania
- DigiDuncan
- DragonMoffon
- Einar Forselv
- Maic Siemering
- pushfoo
- pvcraven
We would also like to thank the contributors who spent their valuable time solving issues, squashing bugs, and writing documentation. We appreciate your help; you helped get 3.0 out the door!
-
DarkLight1337 helped the team untangle type annotation issues for cameras
-
Mohammad Ibrahim was a massive help with the GUI and various other parts of the library.
-
ryyst completely revitalized the Arcade Docs.
- Aizen
- Aurelio Lopez
- BrettskiPy
- Brian Stormont
- cacheguy
- Code Apprentice
- Dominik
- Ethan Chan
- FriendlyGecko
- Grant Hur
- Ian Currie
- Jack Ashwell
- kosvitko
- L Cai
- Miles Curry
- MrWardKKHS
- Natalie Fearnley
- Omar Mohammed
- Raccoon
- Raxeli1
- Rémi Vanicat
- Rich Saupe
- Shadow
- Shivani Arbat
- Snipy7374
- Tiffany Xiao
- Wilson (Fengchi) Wang
Finally, thank you to the Pyglet team! Pyglet is the backbone of Arcade, and this library wouldn't be possible without them.
3.0.0 changes span from Dec 31, 2022 – Jan 25, 2025 (756 days!!)