Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions arcade/sprite.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

import math
from math import sin, cos, radians
import dataclasses
from typing import (
Any,
Expand All @@ -22,7 +23,6 @@
from arcade.geometry_generic import get_angle_degrees
from arcade import load_texture
from arcade import Texture
from arcade import rotate_point
from arcade import make_soft_circle_texture
from arcade import make_circle_texture
from arcade import Color
Expand Down Expand Up @@ -397,24 +397,34 @@ def get_adjusted_hit_box(self) -> PointList:
if self._point_list_cache is not None:
return self._point_list_cache

rad = radians(self._angle)
scale_x, scale_y = self._scale
position_x, position_y = self._position
rad_cos = cos(rad)
rad_sin = sin(rad)

def _adjust_point(point) -> Point:
x, y = point

# Apply scaling
x *= scale_x
y *= scale_y

# Rotate the point if needed
if self._angle:
# Rotate with scaling to not distort it if scale x and y is different
point = rotate_point(point[0] * self._scale[0], point[1] * self._scale[1], 0, 0, self._angle)
# Apply position
return (
point[0] + self._position[0],
point[1] + self._position[1],
)
# Apply position and scale
if rad:
rot_x = x * rad_cos - y * rad_sin
rot_y = x * rad_sin + y * rad_cos
x = rot_x
y = rot_y

# Apply position
return (
point[0] * self._scale[0] + self._position[0],
point[1] * self._scale[1] + self._position[1],
x + position_x,
y + position_y,
)

# Cache the results
self._point_list_cache = tuple(_adjust_point(point) for point in self.hit_box)
self._point_list_cache = tuple([_adjust_point(point) for point in self.hit_box])
return self._point_list_cache

def forward(self, speed: float = 1.0) -> None:
Expand Down
15 changes: 12 additions & 3 deletions arcade/sprite_list/spatial_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,26 @@ def _check_for_collision(sprite1: Sprite, sprite2: Sprite) -> bool:
:returns: True if sprites overlap.
:rtype: bool
"""
radius_sum = max(sprite1._width, sprite1._height) + max(sprite2._width, sprite2._height)
sprite1_position = sprite1._position
sprite1_width = sprite1._width
sprite1_height = sprite1._height
sprite2_position = sprite2._position
sprite2_width = sprite2._width
sprite2_height = sprite2._height
radius_sum = (
(sprite1_width if sprite1_width > sprite1_height else sprite1_height)
+ (sprite2_width if sprite2_width > sprite2_height else sprite2_height)
)
# Multiply by half of the theoretical max diagonal length for an estimation of distance
radius_sum *= 0.71 # 1.42 / 2
radius_sum_x2 = radius_sum * radius_sum

diff_x = sprite1._position[0] - sprite2._position[0]
diff_x = sprite1_position[0] - sprite2_position[0]
diff_x2 = diff_x * diff_x
if diff_x2 > radius_sum_x2:
return False

diff_y = sprite1._position[1] - sprite2._position[1]
diff_y = sprite1_position[1] - sprite2_position[1]
diff_y2 = diff_y * diff_y
if diff_y2 > radius_sum_x2:
return False
Expand Down
1 change: 1 addition & 0 deletions benchmarks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/results.md
54 changes: 54 additions & 0 deletions benchmarks/bench.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# On windows, can run via the bash you get with git:
# C:\Program Files\Git\bin\bash.exe

__dirname="$(CDPATH= cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$__dirname"
cd ..

bench_name="$1"

# I am doing this to ensure it runs against python 3.11, my default install is 3.10
# You can probably remove this line
export PATH="/c/Users/cspot/AppData/Local/Programs/Python/Python311:$PATH"
python.exe --version

# Get current branch name
gitTo=$( git rev-parse --abbrev-ref HEAD )
# Get root of this branch
gitFrom=$( git merge-base origin/development $gitTo )~1
gitCommitRange=$gitFrom..$gitTo

commits=$(git log --format='%H' $gitCommitRange)
commits=$(echo "$commits" | sed -z 's/\n/,/g;s/,$/\n/')
echo "$commits"

hyperfine \
--show-output \
--export-markdown benchmarks/results.md \
--warmup 1 --runs 2 \
--parameter-list commit "$commits,$commits" \
--setup 'git checkout {commit}' \
'python -m benchmarks.'"$bench_name"'.bench {commit}'

git checkout $gitTo

# Postprocess hyperfine's report to include commit messages and github links
python -c '
import subprocess
import re

report_path = "benchmarks/results.md"
with open(report_path,"r") as file:
report = file.read()

def replace(x):
commit = x[1]
result = subprocess.run(["git", "log", "-n1", "--oneline", commit], capture_output=True, encoding="utf-8")
message = result.stdout.strip()
return f"[{message}](https://github.com/pythonarcade/arcade/commit/{commit})"
report = re.sub(r".*? ([a-f0-9]{40})`", replace, report)

with open(report_path,"w") as file:
file.write(report)
'
74 changes: 74 additions & 0 deletions benchmarks/collisions/bench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import math
import arcade
import pyglet
import random
import time

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

WALL_DIM_MIN = 10
WALL_DIM_MAX = 200
WALLS_COUNT = 10

BULLET_VELOCITY_MIN = 1/60
BULLET_VELOCITY_MAX = 10/60
BULLET_COUNT = 1000

SIMULATE_MINUTES = 1
SIMULATE_FPS = 60

# Predictable randomization so that each benchmark is identical
rng = random.Random(0)

bullets = arcade.SpriteList()
walls = arcade.SpriteList()

window = arcade.Window()

# Seed chosen manually to create a wall distribution that looked good enough,
# like something I might create in a game.
rng.seed(2)
for i in range(0, WALLS_COUNT):
wall = arcade.SpriteSolidColor(rng.randint(WALL_DIM_MIN, WALL_DIM_MAX), rng.randint(WALL_DIM_MIN, WALL_DIM_MAX), arcade.color.BLACK)
wall.position = rng.randint(0, SCREEN_WIDTH), rng.randint(0, SCREEN_HEIGHT)
walls.append(wall)

for i in range(0, BULLET_COUNT):
# Create a new bullet
new_bullet = arcade.SpriteCircle(color=arcade.color.RED, radius=10)
new_bullet.position = (rng.randint(0, SCREEN_WIDTH), rng.randint(0, SCREEN_HEIGHT))
speed = rng.random() * (BULLET_VELOCITY_MAX - BULLET_VELOCITY_MIN) + BULLET_VELOCITY_MIN
angle = rng.random() * math.pi * 2
new_bullet.velocity = (math.cos(angle) * speed, math.sin(angle) * speed)
# Half of bullets are rotated, to test those code paths
if rng.random() > 0.5:
new_bullet.angle = 45
bullets.append(new_bullet)

for i in range(0, int(SIMULATE_MINUTES * 60 * SIMULATE_FPS)):
pyglet.clock.tick()

window.switch_to()
window.dispatch_events()

# Move all bullets
for bullet in bullets:
bullet.position = (bullet.position[0] + bullet.velocity[0], bullet.position[1] + bullet.velocity[1])

# Check for collisions
bullets_w_collision = []
for bullet in bullets:
walls_hit = arcade.check_for_collision_with_list(bullet, walls)
if walls_hit:
bullets_w_collision.append(bullet)
for bullet in bullets_w_collision:
# bullets.remove(bullet)
bullet.position = (rng.randint(0, SCREEN_WIDTH), rng.randint(0, SCREEN_HEIGHT))

window.dispatch_event('on_draw')

window.clear(color=arcade.color.WHITE)
walls.draw()
bullets.draw()
window.flip()