Skip to content

Commit 38b5b4a

Browse files
authored
test(gui): add camera tests for rotation and zoom (#2206)
* test(gui): add camera tests for rotation and zoom * fix(gui): gui test broke due to resized window * fix(gui): cleanup camera example closes #2162
1 parent 8ecd746 commit 38b5b4a

4 files changed

Lines changed: 40 additions & 31 deletions

File tree

arcade/gui/examples/gui_and_camera.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""
2-
Arrange widgets in vertical or horizontal lines with UIBoxLayout
2+
This example shows how to use arcade.gui with a camera.
3+
It is a simple game where the player can move around and collect coins.
4+
The player can upgrade their speed and the spawn rate of the coins.
5+
The game has a timer and ends after 60 seconds.
6+
The game is controlled with the arrow keys or WASD.
37
4-
The direction UIBoxLayout follows is controlled by the `vertical` keyword
5-
argument. It is True by default. Pass False to it to arrange elements in
6-
a horizontal line.
8+
At the beginning of the game, the UI camera is used, to apply some animations.
79
810
If arcade and Python are properly installed, you can run this example with:
911
python -m arcade.gui.examples.gui_and_camera
@@ -26,7 +28,7 @@ class MyCoinGame(UIView):
2628
basic GUI setup. We add UIManager to the view under `self.ui`.
2729
2830
The example showcases how to:
29-
- use UIView to setup a basic GUI
31+
- use UIView to set up a basic GUI
3032
- add a button to the view and connect it to a function
3133
- use camera to move the view
3234
@@ -37,8 +39,8 @@ def __init__(self):
3739

3840
# basic camera setup
3941
self.keys = set()
40-
self.ingame_camera = arcade.Camera2D()
41-
self.ingame_camera.bottom_left = 100, 100
42+
self.in_game_camera = arcade.Camera2D()
43+
self.in_game_camera.bottom_left = 100, 100
4244

4345
# in-game counter
4446
self._total_time = 0
@@ -157,7 +159,7 @@ def upgrade_spawn_rate(event: UIOnClickEvent):
157159
self.cam_pos = self.ui.camera.position
158160

159161
def on_draw_before_ui(self):
160-
self.ingame_camera.use() # use the in-game camera to draw in-game objects
162+
self.in_game_camera.use() # use the in-game camera to draw in-game objects
161163
self.sprites.draw()
162164
self.coins.draw()
163165

@@ -212,7 +214,7 @@ def on_update(self, delta_time: float) -> Optional[bool]:
212214
self.player.top -= self._player_speed
213215

214216
# move the camera with the player
215-
self.ingame_camera.position = self.player.position
217+
self.in_game_camera.position = self.player.position
216218

217219
# collect coins
218220
collisions = self.player.collides_with_list(self.coins)
@@ -246,9 +248,6 @@ def on_key_press(self, symbol: int, modifiers: int) -> Optional[bool]:
246248
arcade.close_window()
247249
if symbol == arcade.key.ENTER:
248250
self.window.show_view(MyCoinGame())
249-
if symbol == arcade.key.SPACE:
250-
# Allows user to rotate camera to show off full functionality of the ui camera
251-
self.ui.camera.angle += 5
252251

253252
return False
254253

@@ -259,7 +258,7 @@ def on_key_release(self, symbol: int, modifiers: int) -> Optional[bool]:
259258

260259

261260
if __name__ == "__main__":
262-
window = arcade.Window(1280, 720, "CoinGame Example", resizable=True)
261+
window = arcade.Window(1280, 720, "CoinGame Example", resizable=False)
263262
window.background_color = arcade.color.DARK_BLUE_GRAY
264263
window.show_view(MyCoinGame())
265264
window.run()

arcade/gui/view.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ def __init__(self):
2121
self.ui = UIManager()
2222

2323
def on_show_view(self):
24+
"""If subclassing UIView, don't forget to call super().on_show_view()."""
2425
self.ui.enable()
2526

2627
def on_hide_view(self):
28+
"""If subclassing UIView, don't forget to call super().on_hide_view()."""
2729
self.ui.disable()
2830

2931
def on_draw(self):

tests/conftest.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
if os.environ.get("ARCADE_PYTEST_USE_RUST"):
77
import arcade_accelerate # pyright: ignore [reportMissingImports]
8+
89
arcade_accelerate.bootstrap()
910

1011
import pytest
@@ -24,10 +25,10 @@
2425
OFFSCREEN = None
2526

2627

27-
def create_window(width=800, height=600, caption="Testing", **kwargs):
28+
def create_window(width=1280, height=720, caption="Testing", **kwargs):
2829
global WINDOW
2930
if not WINDOW:
30-
WINDOW = REAL_WINDOW_CLASS(title="Testing", vsync=False, antialiasing=False)
31+
WINDOW = REAL_WINDOW_CLASS(width=width, height=height, title=caption, vsync=False, antialiasing=False)
3132
WINDOW.set_vsync(False)
3233
# This value is being monkey-patched into the Window class so that tests can identify if we are using
3334
# arcade-accelerate easily in case they need to disable something when it is enabled.
@@ -151,7 +152,7 @@ def aspect_ratio(self):
151152
@property
152153
def mouse(self):
153154
return self.window.mouse
154-
155+
155156
@property
156157
def keyboard(self):
157158
return self.window.keyboard
@@ -174,7 +175,7 @@ def current_camera(self):
174175
@property
175176
def _start_finish_render_data(self):
176177
return self.window._start_finish_render_data
177-
178+
178179
@_start_finish_render_data.setter
179180
def _start_finish_render_data(self, data):
180181
self.window._start_finish_render_data = data
@@ -193,7 +194,7 @@ def flip(self):
193194

194195
def on_draw(self):
195196
return self.window.on_draw()
196-
197+
197198
def on_update(self, dt):
198199
return self.window.on_update(dt)
199200

@@ -294,10 +295,12 @@ def window_proxy():
294295
arcade.Window = WindowProxy
295296

296297
_open_window = arcade.open_window
298+
297299
def open_window(*args, **kwargs):
298300
window = create_window(*args, **kwargs)
299301
prepare_window(window)
300302
return window
303+
301304
arcade.open_window = open_window
302305

303306
yield None
@@ -307,7 +310,6 @@ def open_window(*args, **kwargs):
307310

308311
# --- Fixtures for offscreen rendering
309312
class Offscreen:
310-
311313
def __init__(self):
312314
self.ctx = WINDOW.ctx
313315
self.texture = self.ctx.texture((1280, 720), components=4)

tests/unit/gui/test_uimanager_camera.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from unittest.mock import Mock
22

3-
import pytest
4-
53
import arcade
64
from arcade import LBWH
75
from arcade.gui import UIFlatButton
@@ -36,21 +34,29 @@ def test_ui_manager_use_positioned_camera(uimanager, window):
3634
assert button.on_click.called
3735

3836

39-
@pytest.mark.skip("Rotation still work in progress")
4037
def test_ui_manager_use_rotated_camera(uimanager, window):
4138
# GIVEN
42-
clicked = False
43-
4439
button = uimanager.add(UIFlatButton(text="BottomLeftButton", width=100, height=100))
45-
46-
@button.event("on_click")
47-
def on_click(event):
48-
nonlocal clicked
49-
clicked = True
40+
button.on_click = Mock()
5041

5142
# WHEN
5243
uimanager.camera.angle = 90
53-
uimanager.click(150, 150)
44+
x, y = uimanager.camera.project((50, 50))
45+
uimanager.click(x, y)
5446

5547
# THEN
56-
assert clicked
48+
assert button.on_click.called, (uimanager.camera.project((50, 50)), window.size)
49+
50+
51+
def test_ui_manager_use_zoom_camera(uimanager, window):
52+
# GIVEN
53+
button = uimanager.add(UIFlatButton(text="BottomLeftButton", width=100, height=100))
54+
button.on_click = Mock()
55+
56+
# WHEN
57+
uimanager.camera.zoom = 0.9
58+
x, y = uimanager.camera.project((50, 50))
59+
uimanager.click(x, y)
60+
61+
# THEN
62+
assert button.on_click.called

0 commit comments

Comments
 (0)