From 1b5c70d31bcfa446b564861e12433dbab91d2a57 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 05:59:27 -0400 Subject: [PATCH 01/29] Replace parts of BasicSprite via Vec2 + shim props --- arcade/sprite/base.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 00f9757fc..955288e7f 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -42,8 +42,9 @@ class BasicSprite: __slots__ = ( "_position", "_depth", - "_width", - "_height", + "_size", + #"_width", + #"_height", "_scale", "_color", "_texture", @@ -63,13 +64,16 @@ def __init__( visible: bool = True, **kwargs: Any, ) -> None: - self._position = (center_x, center_y) + + position = Vec2(center_x, center_y) # Will be used below + self._position: Vec2 = position self._depth = 0.0 self._texture = texture - width, height = texture.size - self._width = width * scale - self._height = height * scale - self._scale = (scale, scale) + + scale = Vec2(scale, scale) # Will be used below + self._scale: Vec2 = scale + self._size: Vec2 = scale * texture.size + self._visible = bool(visible) self._color: Color = WHITE self.sprite_lists: list["SpriteList"] = [] @@ -78,10 +82,19 @@ def __init__( # Core properties we don't use, but spritelist expects it self._angle = 0.0 - self._hit_box = HitBox(self._texture.hit_box_points, self._position, self._scale) + self._hit_box = HitBox(self._texture.hit_box_points, position, scale) # --- Core Properties --- + # Temp Vec2 test compat stubs for things which expect them + @property + def _width(self) -> float: + return self._size[0] + + @property + def _height(self) -> float: + return self._size[1] + @property def position(self) -> Point2: """Get or set the center x and y position of the sprite.""" From 35fc6cdb8a422240c7e09ad2480d48ff6a297d95 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 06:48:25 -0400 Subject: [PATCH 02/29] First pass of Vec2-ing --- arcade/sprite/base.py | 62 +++++++++++++++++++---------------------- arcade/sprite/sprite.py | 29 ++++++++++--------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 955288e7f..aa399c93b 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -105,8 +105,9 @@ def position(self, new_value: Point2): if new_value == self._position: return - self._position = new_value - self._hit_box.position = new_value + new_value_vec2 = Vec2(*new_value) + self._position = new_value_vec2 + self._hit_box.position = new_value_vec2 self.update_spatial_hash() for sprite_list in self.sprite_lists: @@ -157,14 +158,15 @@ def depth(self, new_value: float): @property def width(self) -> float: """Get or set width or the sprite in pixels""" - return self._width + return self._size[0] @width.setter def width(self, new_value: float): if new_value != self._width: - self._scale = new_value / self._texture.width, self._scale[1] - self._hit_box.scale = self._scale - self._width = new_value + new_scale = Vec2(new_value / self._texture.width, self._scale[1]) + self._scale = new_scale + self._hit_box.scale = new_scale + self._size = (new_value, self.size[1]) self.update_spatial_hash() for sprite_list in self.sprite_lists: @@ -178,27 +180,29 @@ def height(self) -> float: @height.setter def height(self, new_value: float): if new_value != self._height: - self._scale = self._scale[0], new_value / self._texture.height - self._hit_box.scale = self._scale - self._height = new_value + new_scale = Vec2(self._scale[0], new_value / self._texture.height) + self._scale = new_scale + self._hit_box.scale = new_scale + self._size = Vec2(self._size[0], new_value) self.update_spatial_hash() for sprite_list in self.sprite_lists: sprite_list._update_height(self) @property - def size(self) -> Point: + def size(self) -> Vec2: """ Get or set the size of the sprite as a pair of values. This is faster than getting or setting width and height separately. """ - return self._width, self._height + return self._size @size.setter def size(self, new_value: Point2): try: width, height = new_value + size_vec2 = Vec2(width, height) except ValueError: raise ValueError( "size must be a tuple-like object which unpacks to exactly 2 coordinates" @@ -207,12 +211,11 @@ def size(self, new_value: Point2): raise TypeError( "size must be a tuple-like object which unpacks to exactly 2 coordinates" ) + if width != self.width or height != self.height: + texture_size = self._texture.size - if width != self._width or height != self._height: - texture_width, texture_height = self._texture.size - self._scale = width / texture_width, height / texture_height - self._width = width - self._height = height + self._scale = size_vec2 / texture_size + self._size = size_vec2 self.update_spatial_hash() @@ -321,13 +324,13 @@ def scale(self) -> Vec2: @scale.setter def scale(self, new_scale: Point2 | AsFloat): if isinstance(new_scale, (float, int)): - scale_x = new_scale - scale_y = new_scale + scale_vec2 = Vec2(new_scale, new_scale) else: # Treat it as some sort of iterable or sequence # Don't abstract this. Keep it here since it's a hot code path try: scale_x, scale_y = new_scale # type / length implicit check + scale_vec2 = Vec2(scale_x, scale_y) except ValueError: raise ValueError( "scale must be a tuple-like object which unpacks to exactly 2 coordinates" @@ -337,15 +340,12 @@ def scale(self, new_scale: Point2 | AsFloat): "scale must be a tuple-like object which unpacks to exactly 2 coordinates" ) - new_scale = scale_x, scale_y - if new_scale == self._scale: + if scale_vec2 == self._scale: return - self._hit_box.scale = new_scale - tex_width, tex_height = self._texture.size - self._scale = new_scale - self._width = tex_width * scale_x - self._height = tex_height * scale_y + self._hit_box.scale = scale_vec2 + self._scale = scale_vec2 + self._size = self._texture.size * scale_vec2 self.update_spatial_hash() for sprite_list in self.sprite_lists: @@ -659,6 +659,7 @@ def rescale_relative_to_point(self, point: Point2, scale_by: AsFloat | Point2) - factor_x, factor_y = scale_by if factor_x == 1.0 and factor_y == 1.0: return + except ValueError: raise ValueError( "factor must be a float, int, or tuple-like " @@ -670,14 +671,9 @@ def rescale_relative_to_point(self, point: Point2, scale_by: AsFloat | Point2) - ) # set the scale and, if this sprite has a texture, the size data - old_scale_x, old_scale_y = self._scale - new_scale_x = old_scale_x * factor_x - new_scale_y = old_scale_y * factor_y - self._scale = new_scale_x, new_scale_y - - tex_width, tex_height = self._texture.size - self._width = tex_width * new_scale_x - self._height = tex_height * new_scale_y + scale_vec2 = Vec2(factor_x, factor_y) * self._scale + self._scale = scale_vec2 + self._size = scale_vec2 * self._texture.size # If the scaling point is the sprite's center, it doesn't move old_position = self._position diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index 1a31ce6c0..da267bc4d 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -4,6 +4,8 @@ from pathlib import Path from typing import TYPE_CHECKING, Any +from pyglet.math import Vec2 + import arcade from arcade import Texture from arcade.hitbox import HitBox, RotatableHitBox @@ -99,7 +101,7 @@ def __init__( self._angle = angle # Movement - self._velocity = 0.0, 0.0 + self._velocity: Vec2 = Vec2(0.0, 0.0) self.change_angle: float = 0.0 """Change in angle per 1/60th of a second.""" @@ -150,8 +152,7 @@ def __init__( self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle) - self._width = self._texture.width * scale - self._height = self._texture.height * scale + self._size = self._texture.size * self._scale # --- Properties --- @@ -206,7 +207,7 @@ def velocity(self) -> Point2: @velocity.setter def velocity(self, new_value: Point2) -> None: - self._velocity = new_value + self._velocity = Vec2(*new_value) @property def change_x(self) -> float: @@ -215,7 +216,7 @@ def change_x(self) -> float: @change_x.setter def change_x(self, new_value: float) -> None: - self._velocity = new_value, self._velocity[1] + self._velocity = Vec2(new_value, self._velocity[1]) @property def change_y(self) -> float: @@ -224,7 +225,7 @@ def change_y(self) -> float: @change_y.setter def change_y(self, new_value: float) -> None: - self._velocity = self._velocity[0], new_value + self._velocity = Vec2(self._velocity[0], new_value) @property def hit_box(self) -> HitBox: @@ -266,8 +267,8 @@ def texture(self, texture: Texture) -> None: ) self._texture = texture - self._width = texture.width * self._scale[0] - self._height = texture.height * self._scale[1] + self._size = texture.size * self._size + self.update_spatial_hash() for sprite_list in self.sprite_lists: sprite_list._update_texture(self) @@ -293,8 +294,7 @@ def forward(self, speed: float = 1.0) -> None: speed: The speed at which the sprite moves. """ angle_rad = math.radians(self.angle) - self.center_x += math.sin(angle_rad) * speed - self.center_y += math.cos(angle_rad) * speed + self.position += Vec2(0.0, speed).rotate(angle_rad) def reverse(self, speed: float = 1.0) -> None: """ @@ -303,7 +303,8 @@ def reverse(self, speed: float = 1.0) -> None: Args: speed: The speed at which the sprite moves. """ - self.forward(-speed) + angle_rad = math.radians(self.angle) + self.position -= Vec2(0.0, speed).rotate(angle_rad) def strafe(self, speed: float = 1.0) -> None: """ @@ -313,8 +314,10 @@ def strafe(self, speed: float = 1.0) -> None: speed: The speed at which the sprite moves. """ angle_rad = math.radians(self.angle + 90) - self.center_x += math.sin(angle_rad) * speed - self.center_y += math.cos(angle_rad) * speed + self.position += Vec2( + math.sin(angle_rad) * speed, + math.cos(angle_rad) * speed + ) def turn_right(self, theta: float = 90.0) -> None: """ From c62bc5ef592e6073870d1d3efd5fae80b88bcd1b Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 06:51:08 -0400 Subject: [PATCH 03/29] development-portable optimization: stop having 2 levels of indirection for change_* --- arcade/sprite/sprite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index da267bc4d..ebe6eb640 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -212,7 +212,7 @@ def velocity(self, new_value: Point2) -> None: @property def change_x(self) -> float: """Get or set the velocity in the x plane of the sprite.""" - return self.velocity[0] + return self._velocity[0] @change_x.setter def change_x(self, new_value: float) -> None: @@ -221,7 +221,7 @@ def change_x(self, new_value: float) -> None: @property def change_y(self) -> float: """Get or set the velocity in the y plane of the sprite.""" - return self.velocity[1] + return self._velocity[1] @change_y.setter def change_y(self, new_value: float) -> None: From 678918a1b76616e9f25493101094eafc38df6990 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 06:52:00 -0400 Subject: [PATCH 04/29] Make .velocity return Vec2 --- arcade/sprite/sprite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index ebe6eb640..91753eeae 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -192,7 +192,7 @@ def radians(self, new_value: float) -> None: self.angle = new_value * 180.0 / math.pi @property - def velocity(self) -> Point2: + def velocity(self) -> Vec2: """ Get or set the velocity of the sprite. From c8f36cdd2feb74539f767df736fef94f95afe491 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 06:53:09 -0400 Subject: [PATCH 05/29] Make stop set a Vec2 w/o indirection --- arcade/sprite/sprite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index 91753eeae..907069b59 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -341,7 +341,7 @@ def stop(self) -> None: """ Stop the Sprite's motion by setting the velocity and angle change to 0. """ - self.velocity = 0, 0 + self._velocity = Vec2(0, 0) self.change_angle = 0.0 # ----Update Methods ---- From 2b90284cf4373f07cc4c8824d67f209d8d47ab62 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:01:46 -0400 Subject: [PATCH 06/29] Get more types correct + some micro cleanup per Dragon's advice --- arcade/sprite/base.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index aa399c93b..5c0c89d2b 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -96,8 +96,13 @@ def _height(self) -> float: return self._size[1] @property - def position(self) -> Point2: - """Get or set the center x and y position of the sprite.""" + def position(self) -> Vec2: + """ + Get or set the center x and y position of the sprite. + + Returns: + (center_x, center_y) + """ return self._position @position.setter @@ -234,16 +239,16 @@ def scale_x(self) -> float: @scale_x.setter def scale_x(self, new_scale_x: AsFloat): - old_scale_x, old_scale_y = self._scale - if new_scale_x == old_scale_x: + old_scale = self._scale + if new_scale_x == old_scale[0]: return - new_scale = (new_scale_x, old_scale_y) + new_scale = Vec2(new_scale_x, old_scale[1]) # Apply scale to hitbox first to raise any exceptions quickly self._hit_box.scale = new_scale self._scale = new_scale - self._width = self._texture.width * new_scale_x + self._size = Vec2(self._texture.width * new_scale_x, self._size[1]) self.update_spatial_hash() for sprite_list in self.sprite_lists: From a2dab4b8335a457ba764742ea1e877ffd2c3cf0c Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:16:37 -0400 Subject: [PATCH 07/29] Update for sprites now takes dt --- arcade/sprite/sprite.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index 907069b59..ff6531393 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -363,10 +363,7 @@ def update(self, delta_time: float = 1 / 60, *args, **kwargs) -> None: # Users can define these values in any unit they want, but this breaks # compatibility with physics engines. Consider changing this in the future. delta_time *= 60 - self.position = ( - self._position[0] + self.change_x * delta_time, - self._position[1] + self.change_y * delta_time, - ) + self.position += self._velocity * delta_time self.angle += self.change_angle * delta_time # ----Utility Methods---- From 1e48567bf94836202f0905e09691b9d775062e74 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:18:45 -0400 Subject: [PATCH 08/29] Clean up use of ._width in width setter --- arcade/sprite/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 5c0c89d2b..5e298d4ae 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -167,11 +167,12 @@ def width(self) -> float: @width.setter def width(self, new_value: float): - if new_value != self._width: + size = self._size + if new_value != size[0]: new_scale = Vec2(new_value / self._texture.width, self._scale[1]) self._scale = new_scale self._hit_box.scale = new_scale - self._size = (new_value, self.size[1]) + self._size = (new_value, size[1]) self.update_spatial_hash() for sprite_list in self.sprite_lists: From 45684c73f3361fa919bd5411b9709f18d0dfc908 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:19:42 -0400 Subject: [PATCH 09/29] Clean up use of self._height in height property --- arcade/sprite/base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 5e298d4ae..35a925420 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -181,15 +181,16 @@ def width(self, new_value: float): @property def height(self) -> float: """Get or set the height of the sprite in pixels.""" - return self._height + return self._size[1] @height.setter def height(self, new_value: float): - if new_value != self._height: + size = self._size + if new_value != size[1]: new_scale = Vec2(self._scale[0], new_value / self._texture.height) self._scale = new_scale self._hit_box.scale = new_scale - self._size = Vec2(self._size[0], new_value) + self._size = Vec2(size[0], new_value) self.update_spatial_hash() for sprite_list in self.sprite_lists: From b54e852355e0e584f9d84edf3fae61674b34b57d Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:20:55 -0400 Subject: [PATCH 10/29] scale_y setter consistency tweak --- arcade/sprite/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 35a925420..1b050545a 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -272,7 +272,7 @@ def scale_y(self, new_scale_y: AsFloat): if new_scale_y == old_scale_y: return - new_scale = (old_scale_x, new_scale_y) + new_scale = Vec2(old_scale_x, new_scale_y) # Apply scale to hitbox first to raise any exceptions quickly self._hit_box.scale = new_scale From 0cdf2a2de6c11f3dbc395353beb94b8beb13aef2 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:24:55 -0400 Subject: [PATCH 11/29] Inline center_x position updates --- arcade/sprite/base.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 1b050545a..cb679394f 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -125,10 +125,18 @@ def center_x(self) -> float: @center_x.setter def center_x(self, new_value: float): - if new_value == self._position[0]: + position = self._position + if new_value == position[0]: return - self.position = (new_value, self._position[1]) + new_position = Vec2(new_value, position[1]) + + self._position = new_position + self._hit_box.position = new_position + self.update_spatial_hash() + + for sprite_list in self.sprite_lists: + sprite_list._update_position(self) @property def center_y(self) -> float: From aac2ab0317a9c418eaaeb88b9929767bac9d6abe Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:26:30 -0400 Subject: [PATCH 12/29] Inline center_y position update --- arcade/sprite/base.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index cb679394f..85f3dc88a 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -145,10 +145,18 @@ def center_y(self) -> float: @center_y.setter def center_y(self, new_value: float): - if new_value == self._position[1]: + position = self._position + if new_value == position[1]: return - self.position = (self._position[0], new_value) + new_position = (position[0], new_value) + + self._position = new_position + self._hit_box.position = new_position + self.update_spatial_hash() + + for sprite_list in self.sprite_lists: + sprite_list._update_position(self) @property def depth(self) -> float: From 0a7ea89f79eade3dbff05a92cb1b733abb08aeb1 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:30:10 -0400 Subject: [PATCH 13/29] Tweaks to size setter * Keep unpack at top and old-style check * Defer Vec2 creation until know it's different --- arcade/sprite/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 85f3dc88a..a79c869aa 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -225,7 +225,6 @@ def size(self) -> Vec2: def size(self, new_value: Point2): try: width, height = new_value - size_vec2 = Vec2(width, height) except ValueError: raise ValueError( "size must be a tuple-like object which unpacks to exactly 2 coordinates" @@ -234,11 +233,12 @@ def size(self, new_value: Point2): raise TypeError( "size must be a tuple-like object which unpacks to exactly 2 coordinates" ) - if width != self.width or height != self.height: + old_size = self._size + if old_size[0] != width or old_size[1] != height: texture_size = self._texture.size - - self._scale = size_vec2 / texture_size - self._size = size_vec2 + new_size = Vec2(width, height) + self._scale = new_size / texture_size + self._size = new_size self.update_spatial_hash() From 998cba3f5ef0355785cf28caae12eeca4578f000 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:32:36 -0400 Subject: [PATCH 14/29] Replace _height usage in scale_y setter --- arcade/sprite/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index a79c869aa..723c81d74 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -293,7 +293,7 @@ def scale_y(self, new_scale_y: AsFloat): # Apply scale to hitbox first to raise any exceptions quickly self._hit_box.scale = new_scale self._scale = new_scale - self._height = self._texture.height * new_scale_y + self._size = Vec2(self._size[0], self._texture.height * new_scale_y) self.update_spatial_hash() for sprite_list in self.sprite_lists: From 7d2cc9b4c9de8e1e531907ccce769ac2e7606fe5 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:33:10 -0400 Subject: [PATCH 15/29] Remove redundant Vec2 conversion in scale getter --- arcade/sprite/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 723c81d74..1e239db40 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -342,7 +342,7 @@ def scale(self) -> Vec2: and height instead of negatives. """ - return Vec2(*self._scale) + return self._scale @scale.setter def scale(self, new_scale: Point2 | AsFloat): From 40d5d7d4a3b01691ed7ec449811a539039f6c509 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:36:07 -0400 Subject: [PATCH 16/29] Defer Vec2 allocation until after equality check in scale setter --- arcade/sprite/base.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 1e239db40..98f7511dd 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -347,13 +347,13 @@ def scale(self) -> Vec2: @scale.setter def scale(self, new_scale: Point2 | AsFloat): if isinstance(new_scale, (float, int)): - scale_vec2 = Vec2(new_scale, new_scale) + scale_x = new_scale + scale_y = new_scale else: # Treat it as some sort of iterable or sequence # Don't abstract this. Keep it here since it's a hot code path try: scale_x, scale_y = new_scale # type / length implicit check - scale_vec2 = Vec2(scale_x, scale_y) except ValueError: raise ValueError( "scale must be a tuple-like object which unpacks to exactly 2 coordinates" @@ -363,12 +363,14 @@ def scale(self, new_scale: Point2 | AsFloat): "scale must be a tuple-like object which unpacks to exactly 2 coordinates" ) - if scale_vec2 == self._scale: + old_scale = self._scale + if scale_x == old_scale[0] and scale_y == old_scale[1]: return - self._hit_box.scale = scale_vec2 - self._scale = scale_vec2 - self._size = self._texture.size * scale_vec2 + new_scale = Vec2(scale_x, scale_y) + self._hit_box.scale = new_scale + self._scale = new_scale + self._size = self._texture.size * new_scale self.update_spatial_hash() for sprite_list in self.sprite_lists: From faa2eed1904222f13accda030490b12b74e4f091 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:44:30 -0400 Subject: [PATCH 17/29] Comment on strangeness in redundant sprite list updates --- arcade/sprite/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 98f7511dd..19bde2d71 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -713,6 +713,10 @@ def rescale_relative_to_point(self, point: Point2, scale_by: AsFloat | Point2) - (old_y - point_y) * factor_y + point_y, ) + # TODO: this seems potentially redundant given we use .position above + # It's a setter which already rebuilds things, so we probably should + # only rebuild once. + # rebuild all spatial metadata self.update_spatial_hash() for sprite_list in self.sprite_lists: From 892314329af8ed66da9cfbb0971027e52b9cad1c Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:49:14 -0400 Subject: [PATCH 18/29] Fix pyright compat issue due to name reassign --- arcade/sprite/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 19bde2d71..9d8e0e22e 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -70,9 +70,9 @@ def __init__( self._depth = 0.0 self._texture = texture - scale = Vec2(scale, scale) # Will be used below - self._scale: Vec2 = scale - self._size: Vec2 = scale * texture.size + scale_vec2 = Vec2(scale, scale) # Will be used below + self._scale: Vec2 = scale_vec2 + self._size: Vec2 = scale_vec2 * texture.size self._visible = bool(visible) self._color: Color = WHITE @@ -82,7 +82,7 @@ def __init__( # Core properties we don't use, but spritelist expects it self._angle = 0.0 - self._hit_box = HitBox(self._texture.hit_box_points, position, scale) + self._hit_box = HitBox(self._texture.hit_box_points, position, scale_vec2) # --- Core Properties --- From eceb22f1fb2de4b2203ec9e2a6c898c999f08c64 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:55:10 -0400 Subject: [PATCH 19/29] Fix pyright issue and bug in scaling --- arcade/sprite/sprite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index ff6531393..bad3a28d7 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -267,7 +267,7 @@ def texture(self, texture: Texture) -> None: ) self._texture = texture - self._size = texture.size * self._size + self._size = texture.size * self._scale self.update_spatial_hash() for sprite_list in self.sprite_lists: From 91a691d67e9f27f7f130860db737dcf34f3e5e97 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:00:23 -0400 Subject: [PATCH 20/29] Fix more type issues --- arcade/sprite/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 9d8e0e22e..5b4c65697 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -149,7 +149,7 @@ def center_y(self, new_value: float): if new_value == position[1]: return - new_position = (position[0], new_value) + new_position = Vec2(position[0], new_value) self._position = new_position self._hit_box.position = new_position @@ -188,7 +188,7 @@ def width(self, new_value: float): new_scale = Vec2(new_value / self._texture.width, self._scale[1]) self._scale = new_scale self._hit_box.scale = new_scale - self._size = (new_value, size[1]) + self._size = Vec2(new_value, size[1]) self.update_spatial_hash() for sprite_list in self.sprite_lists: From 43027feb8f1da58db39ca97391845e5dbf62b741 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:00:39 -0400 Subject: [PATCH 21/29] Remove redundant scale setting --- arcade/sprite/sprite.py | 1 - 1 file changed, 1 deletion(-) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index bad3a28d7..8c7446942 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -152,7 +152,6 @@ def __init__( self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle) - self._size = self._texture.size * self._scale # --- Properties --- From 598acbee24a5d420b62d717fbb3eced93135c3ad Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:02:03 -0400 Subject: [PATCH 22/29] Fix texture setter --- arcade/sprite/base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 5b4c65697..ca7fe85a8 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -608,8 +608,7 @@ def texture(self, texture: Texture): ) self._texture = texture - self._width = texture.width * self._scale[0] - self._height = texture.height * self._scale[1] + self._size = texture.size * self._scale self.update_spatial_hash() for sprite_list in self.sprite_lists: sprite_list._update_texture(self) From fd16294b018366bba4dd416209b0617568d75299 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:38:13 -0400 Subject: [PATCH 23/29] pyright rmul workaround --- arcade/sprite/base.py | 4 ++-- arcade/sprite/sprite.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index ca7fe85a8..882a9e2d1 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -370,7 +370,7 @@ def scale(self, new_scale: Point2 | AsFloat): new_scale = Vec2(scale_x, scale_y) self._hit_box.scale = new_scale self._scale = new_scale - self._size = self._texture.size * new_scale + self._size = new_scale * self._texture.size self.update_spatial_hash() for sprite_list in self.sprite_lists: @@ -608,7 +608,7 @@ def texture(self, texture: Texture): ) self._texture = texture - self._size = texture.size * self._scale + self._size = self._scale * texture.size self.update_spatial_hash() for sprite_list in self.sprite_lists: sprite_list._update_texture(self) diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index 8c7446942..f1d74446a 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -266,7 +266,7 @@ def texture(self, texture: Texture) -> None: ) self._texture = texture - self._size = texture.size * self._scale + self._size = self._scale * texture.size self.update_spatial_hash() for sprite_list in self.sprite_lists: From 5d65be04b62438063316b4c70de95c526d06892d Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:55:21 -0400 Subject: [PATCH 24/29] Formatting with ./make.py format --- arcade/sprite/base.py | 4 ++-- arcade/sprite/sprite.py | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 882a9e2d1..4825b9b7b 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -43,8 +43,8 @@ class BasicSprite: "_position", "_depth", "_size", - #"_width", - #"_height", + # "_width", + # "_height", "_scale", "_color", "_texture", diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index f1d74446a..d4473ed7c 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -152,7 +152,6 @@ def __init__( self._hit_box: RotatableHitBox = self._hit_box.create_rotatable(angle=self._angle) - # --- Properties --- @property @@ -313,10 +312,7 @@ def strafe(self, speed: float = 1.0) -> None: speed: The speed at which the sprite moves. """ angle_rad = math.radians(self.angle + 90) - self.position += Vec2( - math.sin(angle_rad) * speed, - math.cos(angle_rad) * speed - ) + self.position += Vec2(math.sin(angle_rad) * speed, math.cos(angle_rad) * speed) def turn_right(self, theta: float = 90.0) -> None: """ From 46b10ac9c9bd6053820f1f53b64abfb87124bffd Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 09:27:41 -0400 Subject: [PATCH 25/29] Use early return suggestion from @DragonMoffon --- arcade/sprite/base.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 4825b9b7b..58ec51742 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -184,15 +184,17 @@ def width(self) -> float: @width.setter def width(self, new_value: float): size = self._size - if new_value != size[0]: - new_scale = Vec2(new_value / self._texture.width, self._scale[1]) - self._scale = new_scale - self._hit_box.scale = new_scale - self._size = Vec2(new_value, size[1]) + if new_value == size[0]: + return - self.update_spatial_hash() - for sprite_list in self.sprite_lists: - sprite_list._update_width(self) + new_scale = Vec2(new_value / self._texture.width, self._scale[1]) + self._scale = new_scale + self._hit_box.scale = new_scale + self._size = Vec2(new_value, size[1]) + + self.update_spatial_hash() + for sprite_list in self.sprite_lists: + sprite_list._update_width(self) @property def height(self) -> float: From 60535fc42bc975b1480f74eadbac467078e52a97 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 09:30:52 -0400 Subject: [PATCH 26/29] Apply suggestion from @DragonMoffon in height.setter --- arcade/sprite/base.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 58ec51742..72421db8b 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -204,15 +204,18 @@ def height(self) -> float: @height.setter def height(self, new_value: float): size = self._size - if new_value != size[1]: - new_scale = Vec2(self._scale[0], new_value / self._texture.height) - self._scale = new_scale - self._hit_box.scale = new_scale - self._size = Vec2(size[0], new_value) - self.update_spatial_hash() - for sprite_list in self.sprite_lists: - sprite_list._update_height(self) + if new_value == size[1]: + return + + new_scale = Vec2(self._scale[0], new_value / self._texture.height) + self._scale = new_scale + self._hit_box.scale = new_scale + self._size = Vec2(size[0], new_value) + + self.update_spatial_hash() + for sprite_list in self.sprite_lists: + sprite_list._update_height(self) @property def size(self) -> Vec2: From b428d1a21549d78ba68cb3909d9eaf290532ba7c Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Sun, 7 Jul 2024 09:32:40 -0400 Subject: [PATCH 27/29] Apply same early return style in size.setter --- arcade/sprite/base.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 72421db8b..16064bdf9 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -239,16 +239,18 @@ def size(self, new_value: Point2): "size must be a tuple-like object which unpacks to exactly 2 coordinates" ) old_size = self._size - if old_size[0] != width or old_size[1] != height: - texture_size = self._texture.size - new_size = Vec2(width, height) - self._scale = new_size / texture_size - self._size = new_size + if old_size[0] == width and old_size[1] == height: + return - self.update_spatial_hash() + texture_size = self._texture.size + new_size = Vec2(width, height) + self._scale = new_size / texture_size + self._size = new_size - for sprite_list in self.sprite_lists: - sprite_list._update_size(self) + self.update_spatial_hash() + + for sprite_list in self.sprite_lists: + sprite_list._update_size(self) @property def scale_x(self) -> float: From fbe9050d9bcbb6a19b88f4de7c02ca6a1ccb3c21 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:30:39 -0400 Subject: [PATCH 28/29] Formatting --- arcade/sprite/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index 16064bdf9..b3caace2e 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -206,7 +206,7 @@ def height(self, new_value: float): size = self._size if new_value == size[1]: - return + return new_scale = Vec2(self._scale[0], new_value / self._texture.height) self._scale = new_scale From e168e8272d5eacad972cff1b12440bdcfa163a2d Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:40:07 -0400 Subject: [PATCH 29/29] Replace variable re-assignment with local variable typed purely to Vec2 --- arcade/sprite/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arcade/sprite/base.py b/arcade/sprite/base.py index b3caace2e..bae523e59 100644 --- a/arcade/sprite/base.py +++ b/arcade/sprite/base.py @@ -374,10 +374,10 @@ def scale(self, new_scale: Point2 | AsFloat): if scale_x == old_scale[0] and scale_y == old_scale[1]: return - new_scale = Vec2(scale_x, scale_y) - self._hit_box.scale = new_scale - self._scale = new_scale - self._size = new_scale * self._texture.size + processed_scale: Vec2 = Vec2(scale_x, scale_y) + self._hit_box.scale = processed_scale + self._scale = processed_scale + self._size = processed_scale * self._texture.size self.update_spatial_hash() for sprite_list in self.sprite_lists: