basilisk-engine 0.1.22__py3-none-any.whl → 0.1.24__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

basilisk/__init__.py CHANGED
@@ -8,7 +8,7 @@ from .render.material import Material
8
8
  from .render.shader import Shader
9
9
  from .render.shader_handler import ShaderHandler
10
10
  from .draw import draw
11
- from .render.camera import FreeCamera, StaticCamera, FollowCamera, OrbitCamera
11
+ from .render.camera import FreeCamera, StaticCamera, FollowCamera, OrbitCamera, FixedCamera
12
12
  from .render.sky import Sky
13
13
  from .render.post_process import PostProcess
14
14
  from .particles.particle_handler import ParticleHandler
basilisk/config.py CHANGED
@@ -1,3 +1,4 @@
1
1
  class Config():
2
2
  def __init__(self) -> None:
3
- ...
3
+ self.chunk_size = 40
4
+ self.render_distance = 5
basilisk/draw/draw.py CHANGED
@@ -14,7 +14,7 @@ def rect(engine: Engine, color: tuple, rect: tuple) -> None:
14
14
  """
15
15
 
16
16
  # Get the draw handler from the engine
17
- draw_handler = engine.scene.draw_handler
17
+ draw_handler = engine.draw_handler
18
18
  if not draw_handler: return
19
19
 
20
20
  # Draw the rect
@@ -36,7 +36,7 @@ def circle(engine: Engine, color: tuple, center: tuple, radius: int, resolution:
36
36
  """
37
37
 
38
38
  # Get the draw handler from the engine
39
- draw_handler = engine.scene.draw_handler
39
+ draw_handler = engine.draw_handler
40
40
  if not draw_handler: return
41
41
 
42
42
  # Draw the circle
@@ -57,7 +57,7 @@ def line(engine: Engine, color: tuple, p1: tuple, p2: tuple, thickness: int=1) -
57
57
  """
58
58
 
59
59
  # Get the draw handler from the engine
60
- draw_handler = engine.scene.draw_handler
60
+ draw_handler = engine.draw_handler
61
61
  if not draw_handler: return
62
62
 
63
63
  # Draw the line
@@ -74,10 +74,10 @@ def blit(engine: Engine, image: Image, rect: tuple, alpha: float=1.0):
74
74
  """
75
75
 
76
76
  # Get the draw handler from the engine
77
- draw_handler = engine.scene.draw_handler
77
+ draw_handler = engine.draw_handler
78
78
  if not draw_handler: return
79
79
 
80
- engine.scene.material_handler.image_handler.add(image)
80
+ engine.material_handler.image_handler.add(image)
81
81
 
82
82
  # Blit the image
83
83
  draw_handler.blit(image, rect, alpha)
@@ -88,7 +88,7 @@ def text(engine: Engine, text: str, position: tuple, scale: float=1.0):
88
88
  USE SPARINGLY, INEFFICIENT IMPLAMENTATION
89
89
  """
90
90
 
91
- font_renderer = engine.scene.draw_handler.font_renderer
91
+ font_renderer = engine.draw_handler.font_renderer
92
92
 
93
93
  # Render the text if it has not been cached
94
94
  if text not in font_renderer.text_renders:
@@ -9,9 +9,6 @@ from ..generic.input_validation import validate_color, validate_rect, validate_p
9
9
 
10
10
  class DrawHandler():
11
11
  engine: ...
12
- """Back reference to the parent engine"""
13
- scene: ...
14
- """Back reference to the parent scene"""
15
12
  ctx: mgl.Context
16
13
  """Back reference to the parent context"""
17
14
  program: mgl.Program
@@ -23,15 +20,14 @@ class DrawHandler():
23
20
  vao: mgl.VertexArray=None
24
21
  """VAO for rendering all 2D draw calls"""
25
22
 
26
- def __init__(self, scene) -> None:
23
+ def __init__(self, engine) -> None:
27
24
  # Back references
28
- self.scene = scene
29
- self.engine = scene.engine
30
- self.ctx = scene.engine.ctx
25
+ self.engine = engine
26
+ self.ctx = engine.ctx
31
27
 
32
28
  # Get the shader
33
29
  root = self.engine.root
34
- self.shader = self.scene.shader_handler.add(Shader(self.engine, root + '/shaders/draw.vert', root + '/shaders/draw.frag'))
30
+ self.shader = self.engine.shader_handler.add(Shader(self.engine, root + '/shaders/draw.vert', root + '/shaders/draw.frag'))
35
31
 
36
32
  # Initialize draw data as blank
37
33
  self.draw_data = []
basilisk/engine.py CHANGED
@@ -1,46 +1,50 @@
1
1
  import os
2
2
  from sys import platform
3
- import sys
4
- import glcontext
5
- from .input.path import get_root
6
3
  os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
7
4
  import pygame as pg
8
5
  import moderngl as mgl
6
+ import glcontext # For packaging (so it isnt a hidden import)
7
+ from .render.shader_handler import ShaderHandler
8
+ from .render.material_handler import MaterialHandler
9
+ from .render.frame import Frame
10
+ from .draw.draw_handler import DrawHandler
9
11
  from .config import Config
10
- from .input.mouse import Mouse
12
+ from .input_output.mouse import Mouse
13
+ from .input_output.clock import Clock
14
+ from .input_output.IO_handler import IO
11
15
  from .mesh.cube import Cube
12
- from .render.shader import Shader
13
- import glcontext
14
16
 
15
17
  class Engine():
16
18
  win_size: tuple
17
19
  """Size of the engine window in pixels"""
18
20
  ctx: mgl.Context
19
21
  """ModernGL context used by the engine"""
20
- scene: any
21
- """Scene currently being updated and rendered by the engine"""
22
- clock: pg.Clock
23
- """Pygame clock used to keep track of time between frames"""
22
+ clock: Clock
23
+ """Basilisk clock used to keep track of time"""
24
+ shader_handler: ShaderHandler=None
25
+ """Handler for all shaders used in all scenes of the engine"""
26
+ material_handler: MaterialHandler=None
27
+ """Handler for all materials and images in all scenes"""
28
+ frame: Frame=None
29
+ """Default render target for all locations. Rendered to the screen at the end of the frame"""
24
30
  config: Config
25
31
  """Object containing all global attributes"""
26
32
  delta_time: float
27
33
  """Time in seconds that passed between the last frame"""
28
34
  time: float
29
35
  """Total time the engine has been running"""
30
- running: bool
36
+ running: bool=True
31
37
  """True if the engine is still running"""
32
- events: list
33
- """List of all pygame"""
34
- keys: list
35
- """bool list containing the state of all keys this frame"""
36
- previous_keys: list
37
- """bool list containing the state of all keys at the previous frame"""
38
38
  mouse: Mouse
39
39
  """Object containing information about the user's mouse"""
40
40
  root: str
41
41
  """Path to the root directory containing internal data"""
42
- event_resize: bool
43
- """Bool for if a resize event has occured this frame"""
42
+ current_frame_updated: bool=False
43
+ """Flag for if the engine has been updated this frame"""
44
+ keys: list[bool]
45
+ """List of all keyboard inputs as booleans"""
46
+ previous_keys: list[bool]
47
+ """List of all keyoard inputs from the last frame as booleans"""
44
48
 
45
49
  def __init__(self, win_size=(800, 800), title="Basilisk Engine", vsync=None, max_fps=None, grab_mouse=True, headless=False, resizable=True) -> None:
46
50
  """
@@ -56,34 +60,31 @@ class Engine():
56
60
  Flag for headless rendering
57
61
  """
58
62
 
59
- if platform == 'win32' : self.platform = 'windows'
60
- elif platform == 'darwin': self.platform = 'mac'
61
- else: self.platform = 'linux'
62
-
63
63
  # Save the window size
64
64
  self.win_size = win_size
65
- self.event_resize = None
66
65
 
66
+ # Initialize pygame and set OpenGL attributes
67
67
  pg.init()
68
- # Initialize pygame and OpenGL attributes
69
68
  pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
70
69
  pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
71
70
  pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
72
- # Check vsync against platform defaults
73
- if vsync == None: vsync = True if platform == 'linux' else False
74
- self.max_fps = max_fps
75
- # Pygame display init
71
+
72
+ # Platform settings
73
+ if platform == 'win32' : self.platform = 'windows'
74
+ elif platform == 'darwin': self.platform = 'mac'
75
+ else: self.platform = 'linux'
76
+ if vsync == None: vsync = True if self.platform == 'linux' else False
77
+
78
+ # Initializae the pygame display
79
+ self.headless = headless
76
80
  if headless:
77
81
  pg.display.set_mode((300, 50), vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
78
82
  pg.display.iconify()
79
83
  else:
80
84
  if resizable: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE)
81
85
  else: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
82
-
83
- self.caption = title
84
- if title: pg.display.set_caption(title)
85
-
86
- # Init sound
86
+
87
+ # Initalize pygame sound moduel sound
87
88
  pg.mixer.pre_init(44100, -16, 2, 512)
88
89
  pg.mixer.init()
89
90
  pg.mixer.set_num_channels(64)
@@ -94,102 +95,62 @@ class Engine():
94
95
  self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
95
96
 
96
97
  # Global attributes referenced by the handlers
97
- self.headless = headless
98
- self.set_configurations()
98
+ self.config = Config()
99
99
  self.root = os.path.dirname(__file__)
100
100
  self.cube = Cube(self)
101
101
  self.fbos = []
102
-
103
- # Update the icon
104
- pg.display.set_icon(pg.image.load(self.root + '/bsk_assets/basilisk.png'))
105
102
 
106
- # Time variables
107
- self.clock = pg.time.Clock()
108
- self.delta_time = 0
109
- self.time = 0
103
+ # Handlers
104
+ self.clock = Clock(self, max_fps)
105
+ self.IO = IO(self, grab_mouse=grab_mouse, caption=title)
106
+ self.material_handler = MaterialHandler(self)
107
+ self.shader_handler = ShaderHandler(self)
108
+ self.draw_handler = DrawHandler(self)
109
+ self.frame = Frame(self)
110
+ self.material_handler.set_base()
111
+
112
+ def _update(self) -> None:
113
+ """
114
+ Internal engine update.
115
+ Updates all input, physics, and time variables. Clears the frame.
116
+ """
110
117
 
111
- # Initialize input lists
112
- self.keys = pg.key.get_pressed()
113
- self.previous_keys = self.keys
114
- self.mouse = Mouse(grab=grab_mouse)
118
+ if self.current_frame_updated: return
115
119
 
116
- # Scene being used by the engine
117
- self.scene = None
120
+ for fbo in self.fbos: fbo.clear()
121
+ self.clock.update()
122
+ self.IO.update()
118
123
 
119
- # Load a default shader
120
- self.shader = Shader(self, self.root + '/shaders/batch.vert', self.root + '/shaders/batch.frag')
121
- self.shader.hash = self.shader.hash + hash('engine_shader')
124
+ self.current_frame_updated = True
122
125
 
123
- # Set the scene to running
124
- self.running = True
125
126
 
126
- def update(self, render=True) -> None:
127
+ def update(self) -> None:
127
128
  """
128
- Updates all input, physics, and time variables. Renders the current scene.
129
+ Calls internal update if needed
130
+ Renders the draw handler
131
+ Renders the engine's frame to the screen.
129
132
  """
130
133
 
131
- # Tick the clock and get delta time
132
- if self.max_fps: self.delta_time = self.clock.tick(self.max_fps) / 1000
133
- else: self.delta_time = self.clock.tick() / 1000
134
- self.time += self.delta_time
135
- if not self.caption: pg.display.set_caption(f"FPS: {round(self.clock.get_fps())}")
136
- self.event_resize = False
137
134
 
138
- # Update the previous input lists for the next frame
139
- self.previous_keys = self.keys
140
-
141
- # Get inputs and events
142
- self.events = pg.event.get()
143
- self.keys = pg.key.get_pressed()
144
- self.mouse.update(self.events)
145
-
146
- # Loop through all pygame events
147
- for event in self.events:
148
- if event.type == pg.QUIT: # Quit the engine
149
- self.quit()
150
- return
151
- if event.type == pg.VIDEORESIZE:
152
- # Updates the viewport
153
- self.event_resize = True
154
- self.win_size = (event.w, event.h)
155
- self.ctx.viewport = (0, 0, event.w, event.h)
156
- self.scene.camera.use()
157
- self.scene.frame.resize()
158
- for fbo in self.fbos: fbo.resize()
159
-
160
-
161
- # Update the scene if possible
162
- if self.scene: self.scene.update()
163
- # Render after the scene and engine has been updated
164
- if render: self.render()
165
-
166
-
167
- def render(self) -> None:
168
- """
169
- Renders the scene currently being used by the engine
170
- """
171
-
172
- # Set the ctx for rendering
173
- self.ctx.screen.use()
174
- self.ctx.clear()
135
+ # Must update the frame
136
+ if not self.current_frame_updated: self._update()
137
+ if not self.running: return
175
138
 
176
- # Render the scene
177
- if self.scene:self.scene.render()
139
+ # Render all draw calls from the past frame
140
+ self.frame.use()
141
+ self.draw_handler.render()
178
142
 
179
- # Flip pygame display buffer
143
+ # Clear the screen and render the frame
144
+ self.ctx.screen.use()
145
+ self.ctx.clear()
146
+ self.frame.render()
180
147
  pg.display.flip()
181
148
 
182
- def set_configurations(self):
183
- """
184
- Sets global configurations. These attributs are not used by the engine, just the handlers
185
- """
149
+ self.frame.clear()
186
150
 
187
- # Create a config object
188
- self.config = Config()
189
151
 
190
- # Set the attributes on the config object
191
- setattr(self.config, "chunk_size", 40)
192
- setattr(self.config, "render_distance", 5)
152
+ # Allow for the engine to take in input again
153
+ self.current_frame_updated = False
193
154
 
194
155
  def quit(self) -> None:
195
156
  """
@@ -200,18 +161,10 @@ class Engine():
200
161
  self.ctx.release()
201
162
  self.running = False
202
163
 
203
- @property
204
- def scene(self): return self._scene
164
+
205
165
  @property
206
166
  def shader(self): return self._shader
207
-
208
- @scene.setter
209
- def scene(self, value):
210
- self._scene = value
211
- if self._scene:
212
- self._scene.set_engine(self)
213
-
214
167
  @shader.setter
215
168
  def shader(self, value):
216
169
  self._shader = value
217
- if self.scene: value.set_main()
170
+ value.set_main()
@@ -0,0 +1,92 @@
1
+ import pygame as pg
2
+ from .keys import Keys
3
+ from .mouse import Mouse
4
+
5
+
6
+ class IO:
7
+ keys: Keys=None
8
+ """Handler for all keyboard inputs"""
9
+ mouse: Mouse=None
10
+ """Handler for all mouse inputs and mouse settings"""
11
+ events: list=[]
12
+ """List of all the events in the frame"""
13
+ event_resize: bool=False
14
+ """Bool for if a resize event has occured this frame"""
15
+
16
+ def __init__(self, engine: ..., grab_mouse: bool=True, caption: bool|None="Basilisk") -> None:
17
+ """
18
+ Class to handle all inputs and outputs for the engine.
19
+ """
20
+
21
+ # Reference to parent engine
22
+ self.engine = engine
23
+
24
+ # Caption attrib
25
+ self.caption = caption
26
+ self.update_caption()
27
+
28
+ # Handlers for key and mouse input
29
+ self.keys = Keys(engine)
30
+ self.mouse = Mouse(grab=grab_mouse)
31
+
32
+ # Expose the mouse on the engine level
33
+ setattr(self.engine, "mouse", self.mouse)
34
+
35
+ # Fill in default values for engine attributes
36
+ self.set_engine_attribiutes()
37
+
38
+ # Update the icon for the window
39
+ pg.display.set_icon(pg.image.load(self.engine.root + '/bsk_assets/basilisk.png'))
40
+
41
+ def update(self) -> None:
42
+ """
43
+ Update all inputs and check for events
44
+ """
45
+
46
+ # Get events
47
+ self.events = pg.event.get()
48
+
49
+ # Update the keys and the mouse
50
+ self.keys.update()
51
+ self.mouse.update(self.events)
52
+
53
+ # Handle events and update attributes
54
+ self.get_events()
55
+ self.set_engine_attribiutes()
56
+ self.update_caption()
57
+
58
+ def get_events(self) -> None:
59
+ """
60
+ Loop through all pygame events and make updates as needed
61
+ """
62
+
63
+ # Clear global events
64
+ self.event_resize = False
65
+
66
+
67
+ for event in self.events:
68
+ if event.type == pg.QUIT: # Quit the engine
69
+ self.engine.quit()
70
+ return
71
+ if event.type == pg.VIDEORESIZE:
72
+ # Updates the viewport
73
+ self.event_resize = True
74
+ self.engine.win_size = (event.w, event.h)
75
+ self.engine.ctx.viewport = (0, 0, event.w, event.h)
76
+ for fbo in self.engine.fbos: fbo.resize()
77
+
78
+ def update_caption(self) -> None:
79
+ """
80
+ Updates the window caption with either the fps or the window name. Set to 'Basilisk Engine' by default
81
+ """
82
+
83
+ caption = self.caption if self.caption else f"FPS: {round(self.engine.clock.fps)}"
84
+ pg.display.set_caption(caption)
85
+
86
+ def set_engine_attribiutes(self) -> None:
87
+ """
88
+ Updates engine attributes with this instance's attributes for ease of use
89
+ """
90
+
91
+ setattr(self.engine, "events", self.events)
92
+ setattr(self.engine, "event_resize", self.event_resize)
@@ -0,0 +1,50 @@
1
+ import pygame as pg
2
+
3
+
4
+ class Clock:
5
+ delta_time: float=0
6
+ """The amount of time that passed between the last and current frame"""
7
+ time: float=0
8
+ """Total time that has passed since the start of the program"""
9
+
10
+ def __init__(self, engine, max_fps=None) -> None:
11
+ """
12
+ Class to keep track of all time and delta time in the program
13
+ """
14
+
15
+ # Reference to the parent engine
16
+ self.engine = engine
17
+
18
+ # Create a pygame clock
19
+ self.clock = pg.Clock()
20
+ self.max_fps = max_fps
21
+
22
+ # Default values for attributes
23
+ self.set_engine_attribiutes()
24
+
25
+ def update(self) -> None:
26
+ """Ticks the clock"""
27
+
28
+ # Tick the clock and get delta time in seconds
29
+ if self.max_fps: self.delta_time = self.clock.tick(self.max_fps) / 1000
30
+ else: self.delta_time = self.clock.tick() / 1000
31
+
32
+ # Increment the total time by time since last frame
33
+ self.time += self.delta_time
34
+
35
+ self.set_engine_attribiutes()
36
+
37
+ def set_engine_attribiutes(self) -> None:
38
+ """
39
+ Updates engine attributes with this instance's attributes for ease of use
40
+ """
41
+
42
+ setattr(self.engine, "delta_time", self.delta_time)
43
+ setattr(self.engine, "dt", self.delta_time)
44
+ setattr(self.engine, "time", self.time)
45
+ setattr(self.engine, "fps", self.fps)
46
+
47
+
48
+ @property
49
+ def fps(self) -> float:
50
+ return self.clock.get_fps()
@@ -0,0 +1,44 @@
1
+ import pygame as pg
2
+
3
+
4
+ class Keys:
5
+ current_keys: list[bool]
6
+ """The keys pressed during the current frame"""
7
+ previous_keys: list[bool]
8
+ """The keys pressed in the last frame"""
9
+
10
+ def __init__(self, engine: ...) -> None:
11
+ """
12
+ Handler for all keyboard inputs. Stores data from current and previous frames
13
+ """
14
+
15
+ # Reference to the parent engine
16
+ self.engine = engine
17
+
18
+ # Fill in default values for current and previous keys to aviod startup errors
19
+ self.current_keys = pg.key.get_pressed()
20
+ self.previous_keys = self.current_keys
21
+ self.set_engine_attribiutes()
22
+
23
+
24
+ def update(self) -> None:
25
+ """
26
+ Gets all keyboard inputs and propogates last frame inputs
27
+ """
28
+
29
+ # Get keyboard input
30
+ self.previous_keys = self.current_keys
31
+ # Propogate input to the last frame
32
+ self.current_keys = pg.key.get_pressed()
33
+
34
+ # Expose the attributes on the engine level
35
+ self.set_engine_attribiutes()
36
+
37
+ def set_engine_attribiutes(self) -> None:
38
+ """
39
+ Updates engine attributes with this instance's attributes for ease of use
40
+ """
41
+
42
+ setattr(self.engine, "keys", self.current_keys)
43
+ setattr(self.engine, "previous_keys", self.previous_keys)
44
+ setattr(self.engine, "prev_keys", self.previous_keys)
@@ -0,0 +1,90 @@
1
+ import pygame as pg
2
+
3
+
4
+ class Mouse():
5
+ def __init__(self, grab=True):
6
+ self._position = list(pg.mouse.get_pos())
7
+ self._relative = [0, 0]
8
+ self.buttons = pg.mouse.get_pressed()
9
+ self.previous_buttons = pg.mouse.get_pressed()
10
+ self.grab = grab
11
+ self.visible = not self.grab
12
+
13
+ def update(self, events):
14
+ """
15
+ Updates all mouse state variables.
16
+ Checks for mouse-related events.
17
+ """
18
+
19
+ self._position = list(pg.mouse.get_pos())
20
+ self._relative = list(pg.mouse.get_rel())
21
+ self.previous_buttons = self.buttons
22
+ self.buttons = pg.mouse.get_pressed()
23
+
24
+ for event in events:
25
+ if event.type == pg.KEYUP:
26
+ if event.key == pg.K_ESCAPE and self.grab:
27
+ # Unlock mouse
28
+ self.grab = False
29
+ self.visible = True
30
+ if event.type == pg.MOUSEBUTTONUP and not self.grab:
31
+ # Lock mouse
32
+ self.grab = True
33
+ self.visible = False
34
+
35
+ @property
36
+ def position(self): return self._position
37
+ @property
38
+ def x(self): return self._position[0]
39
+ @property
40
+ def y(self): return self._position[1]
41
+ @property
42
+ def relative(self): return self._relative
43
+ @property
44
+ def relative_x(self): return self._relative[0]
45
+ @property
46
+ def relative_y(self): return self._relative[1]
47
+ @property
48
+ def click(self): return self.buttons[0] and not self.previous_buttons[0]
49
+ @property
50
+ def left_click(self): return self.buttons[0] and not self.previous_buttons[0]
51
+ @property
52
+ def middle_click(self): return self.buttons[1] and not self.previous_buttons[1]
53
+ @property
54
+ def right_click(self): return self.buttons[2] and not self.previous_buttons[2]
55
+ @property
56
+ def left_down(self): return self.buttons[0]
57
+ @property
58
+ def middle_down(self): return self.buttons[1]
59
+ @property
60
+ def right_down(self): return self.buttons[2]
61
+ @property
62
+ def grab(self): return self._grab
63
+ @property
64
+ def visible(self): return self._visable
65
+
66
+ @position.setter
67
+ def position(self, value: tuple[int]) -> tuple[int]:
68
+ self._position = value
69
+ pg.mouse.set_pos(self._position)
70
+ return self._position
71
+ @x.setter
72
+ def x(self, value: int) -> int:
73
+ self._position[0] = value
74
+ pg.mouse.set_pos(self._position)
75
+ return self._position
76
+ @y.setter
77
+ def y(self, value: int) -> int:
78
+ self._position[1] = value
79
+ pg.mouse.set_pos(self._position)
80
+ return self._position
81
+ @grab.setter
82
+ def grab(self, value) -> bool:
83
+ self._grab = value
84
+ pg.event.set_grab(self._grab)
85
+ return self._grab
86
+ @visible.setter
87
+ def visible(self, value) -> bool:
88
+ self._visible = value
89
+ pg.mouse.set_visible(self._visible)
90
+ return self._visible