Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scene improvements #1676

Merged
merged 1 commit into from
Apr 3, 2023
Merged
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
113 changes: 59 additions & 54 deletions arcade/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,20 @@
from arcade.types import Color, RGBA255
from arcade.tilemap import TileMap

from warnings import warn

class Scene:
"""
Class that represents a `scene` object. Most games will use Scenes to render their Sprites.
For examples on how to use this class, see:
https://api.arcade.academy/en/latest/tutorials/views/index.html

Attributes:
:sprite_lists: A list of `SpriteList` objects. The order of this list is the
order in which they will be drawn.
:name_mapping: A dictionary of `SpriteList` objects. This contains the same lists
as the `sprite_lists` attribute, but is a mapping of them by name. This is
not necessarily in the same order as the `sprite_lists` attribute.
"""

def __init__(self) -> None:
self.sprite_lists: List[SpriteList] = []
self.name_mapping: Dict[str, SpriteList] = {}

self._sprite_lists: List[SpriteList] = []
self._name_mapping: Dict[str, SpriteList] = {}
@classmethod
def from_tilemap(cls, tilemap: TileMap) -> "Scene":
"""
Expand All @@ -56,7 +51,7 @@ def get_sprite_list(self, name: str) -> SpriteList:

:param str name: The name of the `SpriteList` to retrieve.
"""
return self.name_mapping[name]
return self._name_mapping[name]

def __getitem__(self, key: str) -> SpriteList:
"""
Expand All @@ -67,8 +62,8 @@ def __getitem__(self, key: str) -> SpriteList:

:param str key: The name of the 'SpriteList' to retreive.
"""
if key in self.name_mapping:
return self.name_mapping[key]
if key in self._name_mapping:
return self._name_mapping[key]

raise KeyError(f"Scene does not contain a layer named: {key}")

Expand All @@ -86,8 +81,8 @@ def add_sprite(self, name: str, sprite: Sprite) -> None:
:param str name: The name of the `SpriteList` to add to or create.
:param Sprite sprite: The `Sprite` to add.
"""
if name in self.name_mapping:
self.name_mapping[name].append(sprite)
if name in self._name_mapping:
self._name_mapping[name].append(sprite)
else:
new_list: SpriteList = SpriteList()
new_list.append(sprite)
Expand All @@ -113,8 +108,11 @@ def add_sprite_list(
"""
if sprite_list is None:
sprite_list = SpriteList(use_spatial_hash=use_spatial_hash)
self.name_mapping[name] = sprite_list
self.sprite_lists.append(sprite_list)
if name in self._name_mapping.keys():
self.remove_sprite_list_by_name(name)
warn("A Spritelist with the name: "+name+", is already in the scene, will override Spritelist")
self._name_mapping[name] = sprite_list
self._sprite_lists.append(sprite_list)

def add_sprite_list_before(
self,
Expand All @@ -138,10 +136,13 @@ def add_sprite_list_before(
"""
if sprite_list is None:
sprite_list = SpriteList(use_spatial_hash=use_spatial_hash)
self.name_mapping[name] = sprite_list
before_list = self.name_mapping[before]
index = self.sprite_lists.index(before_list)
self.sprite_lists.insert(index, sprite_list)
if name in self._name_mapping.keys():
self.remove_sprite_list_by_name(name)
warn("A Spritelist with the name: "+name+", is already in the scene, will override Spritelist")
self._name_mapping[name] = sprite_list
before_list = self._name_mapping[before]
index = self._sprite_lists.index(before_list)
self._sprite_lists.insert(index, sprite_list)

def move_sprite_list_before(
self,
Expand All @@ -157,16 +158,16 @@ def move_sprite_list_before(
:param str name: The name of the SpriteList to move.
:param str before: The name of the SpriteList to place it before.
"""
if name not in self.name_mapping:
if name not in self._name_mapping:
raise ValueError(
f"Tried to move unknown SpriteList with the name {name} in Scene"
)

name_list = self.name_mapping[name]
before_list = self.name_mapping[before]
new_index = self.sprite_lists.index(before_list)
old_index = self.sprite_lists.index(name_list)
self.sprite_lists.insert(new_index, self.sprite_lists.pop(old_index))
name_list = self._name_mapping[name]
before_list = self._name_mapping[before]
new_index = self._sprite_lists.index(before_list)
old_index = self._sprite_lists.index(name_list)
self._sprite_lists.insert(new_index, self._sprite_lists.pop(old_index))

def add_sprite_list_after(
self,
Expand All @@ -190,10 +191,13 @@ def add_sprite_list_after(
"""
if sprite_list is None:
sprite_list = SpriteList(use_spatial_hash=use_spatial_hash)
self.name_mapping[name] = sprite_list
after_list = self.name_mapping[after]
index = self.sprite_lists.index(after_list) + 1
self.sprite_lists.insert(index, sprite_list)
if name in self._name_mapping.keys():
self.remove_sprite_list_by_name(name)
warn("A Spritelist with the name: "+name+", is already in the scene, will override Spritelist")
self._name_mapping[name] = sprite_list
after_list = self._name_mapping[after]
index = self._sprite_lists.index(after_list) + 1
self._sprite_lists.insert(index, sprite_list)

def move_sprite_list_after(
self,
Expand All @@ -209,16 +213,16 @@ def move_sprite_list_after(
:param str name: The name of the SpriteList to move.
:param str after: The name of the SpriteList to place it after.
"""
if name not in self.name_mapping:
if name not in self._name_mapping:
raise ValueError(
f"Tried to move unknown SpriteList with the name {name} in Scene"
)

name_list = self.name_mapping[name]
after_list = self.name_mapping[after]
new_index = self.sprite_lists.index(after_list) + 1
old_index = self.sprite_lists.index(name_list)
self.sprite_lists.insert(new_index, self.sprite_lists.pop(old_index))
name_list = self._name_mapping[name]
after_list = self._name_mapping[after]
new_index = self._sprite_lists.index(after_list) + 1
old_index = self._sprite_lists.index(name_list)
self._sprite_lists.insert(new_index, self._sprite_lists.pop(old_index))

def remove_sprite_list_by_name(
self,
Expand All @@ -231,14 +235,14 @@ def remove_sprite_list_by_name(

:param str name: The name of the SpriteList to remove.
"""
sprite_list = self.name_mapping[name]
self.sprite_lists.remove(sprite_list)
del self.name_mapping[name]
sprite_list = self._name_mapping[name]
self._sprite_lists.remove(sprite_list)
del self._name_mapping[name]

def remove_sprite_list_by_object(self, sprite_list: SpriteList) -> None:
self.sprite_lists.remove(sprite_list)
self.name_mapping = {
key: val for key, val in self.name_mapping.items() if val != sprite_list
self._sprite_lists.remove(sprite_list)
self._name_mapping = {
key: val for key, val in self._name_mapping.items() if val != sprite_list
}

def update(self, names: Optional[List[str]] = None) -> None:
Expand All @@ -253,10 +257,10 @@ def update(self, names: Optional[List[str]] = None) -> None:
"""
if names:
for name in names:
self.name_mapping[name].update()
self._name_mapping[name].update()
return

for sprite_list in self.sprite_lists:
for sprite_list in self._sprite_lists:
sprite_list.update()

def on_update(self, delta_time: float = 1 / 60, names: Optional[List[str]] = None) -> None:
Expand All @@ -273,10 +277,10 @@ def on_update(self, delta_time: float = 1 / 60, names: Optional[List[str]] = Non
"""
if names:
for name in names:
self.name_mapping[name].on_update(delta_time)
self._name_mapping[name].on_update(delta_time)
return

for sprite_list in self.sprite_lists:
for sprite_list in self._sprite_lists:
sprite_list.on_update(delta_time)

def update_animation(
Expand All @@ -294,10 +298,10 @@ def update_animation(
"""
if names:
for name in names:
self.name_mapping[name].update_animation(delta_time)
self._name_mapping[name].update_animation(delta_time)
return

for sprite_list in self.sprite_lists:
for sprite_list in self._sprite_lists:
sprite_list.update_animation(delta_time)

def draw(self, names: Optional[List[str]] = None, **kwargs) -> None:
Expand All @@ -307,7 +311,7 @@ def draw(self, names: Optional[List[str]] = None, **kwargs) -> None:
If `names` parameter is provided then only the specified SpriteLists
will be drawn. They will be drawn in the order that the names in the
list were arranged. If `names` is not provided, then every SpriteList
in the scene will be drawn according the order of the main sprite_lists
in the scene will be drawn according the order of the main _sprite_lists
attribute of the Scene.

:param Optional[List[str]] names: A list of names of SpriteLists to draw.
Expand All @@ -320,10 +324,10 @@ def draw(self, names: Optional[List[str]] = None, **kwargs) -> None:

if names:
for name in names:
self.name_mapping[name].draw(**kwargs)
self._name_mapping[name].draw(**kwargs)
return

for sprite_list in self.sprite_lists:
for sprite_list in self._sprite_lists:
sprite_list.draw(**kwargs)

def draw_hit_boxes(
Expand All @@ -338,14 +342,15 @@ def draw_hit_boxes(
If `names` parameter is provided then only the specified SpriteLists
will be drawn. They will be drawn in the order that the names in the
list were arranged. If `names` is not provided, then every SpriteList
in the scene will be drawn according to the order of the main sprite_lists
in the scene will be drawn according to the order of the main _sprite_lists
attribute of the Scene.
"""

if names:
for name in names:
self.name_mapping[name].draw_hit_boxes(color, line_thickness)
self._name_mapping[name].draw_hit_boxes(color, line_thickness)
return

for sprite_list in self.sprite_lists:
for sprite_list in self._sprite_lists:
sprite_list.draw_hit_boxes(color, line_thickness)