pythonarcade / arcade

Easy to use Python library for creating 2D arcade games.
http://arcade.academy
Other
1.69k stars 319 forks source link

Feature Request: "Sections" to Improve View handling #1070

Closed alejcas closed 2 years ago

alejcas commented 2 years ago

Enhancement request:

What would it help with?

In a simple game, the whole viewport is used to display the game "map". In more advanced games it's fairly normal to have this viewport divided into "sections". Areas where different information is displayed. For example you can have a menu at the top, some info panel at the right and the game main "screen" (the "map") covering the rest of the viewport.

When dealing with such circumstances, in the current state of arcade is somehow complicated to isolate events occurring in the different sections of the viewport.

What I propose is to enhance the View object to incorporate the optional ability to add Sections. The user can then define a Section defining a left, bottom, width and height inside the screen dimensions (or bigger). Then the view's SectionManager will automatically redirect any events to that Section without interfering with other sections or the View itself.

What should be added/changed?

What I can help with?

I've currently developed the code needed for this. It's totally optional and if the user chooses to not use Sections then the "code flow" is the same as it is now without any performance penalty.

I would like to push this code to some branch so you can take a look at the code.

benjamin-kirkbride commented 2 years ago

I love this idea.

Question, would something like this work for a mini-map as well?

eruvanos commented 2 years ago

For the GUI this problem will be solved in the next release. With the right setup (enable UIManager within on_showview) the UIManager gets the events first and passes them to a Widget, if a widget "consumes" (returns True in on...() ) an event, they are not passed to the View or Window.

alejcas commented 2 years ago

For the GUI this problem will be solved in the next release. With the right setup (enable UIManager within on_showview) the UIManager gets the events first and passes them to a Widget, if a widget "consumes" (returns True in on...() ) an event, they are not passed to the View or Window.

Ok, but this has nothing to do with UI elements. This just redirects events and automate certain things (cameras, etc.) to "Section" objects that represents a certain portion of the viewport. This actually isolates the event handling so these are triggered in the correct portion of your code. Just where they are needed.

It also shouldn't impact UI events or any UI related content.

alejcas commented 2 years ago

Question, would something like this work for a mini-map as well?

I'm making a pseudo game where I have a menu bar at the top (with buttons and dropdowns) and an info panel on the right. The center is the actual game map. The info panel has many things but a minimap is a part of it. Using the "Sections" approach, the right panel will become a "Section" subclass and it should handle all it's contents (like the minimap and more) receiving only the events triggered in that same portion of the screen.

alejcas commented 2 years ago

Check https://github.com/janscas/arcade/commit/c3e6268908168d5e9fa3da949027ea9c6634b738

benjamin-kirkbride commented 2 years ago

@janscas

I have a menu bar at the top (with buttons and dropdowns)

How will the dropdown work if it goes past the border of the Section?

Would something like this work for a modal/window type element as well?

alejcas commented 2 years ago

How will the dropdown work if it goes past the border of the Section?

Good question! To catch the event (in case you needed which I don't because the UI elements will catch that event anyway as noted by @eruvanos) you just have to override the section method is_mouse_on_top so it answers the question correctly. The section also need to be in front of other sections that overlap on the dropdown position out of the section boundaries.

Would something like this work for a modal/window type element as well?

Yes, but for the moment sections can't overlap. This is in my mind, we just need to handle the section event propagation and the section order in the SectionManager. Very little effort to allow this.

alejcas commented 2 years ago

By the way, modals can just be a Section that is at the beginnig of all other sections on the SectionManager and occupies the whole viewport but just draws a portion of it. So all events will go to that section without triggering any other section / view events. ;)

Just wanted to know the devs opinion into this before putting to much effort.

benjamin-kirkbride commented 2 years ago

I think that this possibly spawns a larger discussion about views/subviews and how that would relate to Sections.

Thoughts @Cleptomania ?

pvcraven commented 2 years ago

You can create a PR, or just fork the project and show it here. I like the idea. Could be complex though, esp with event management.

alejcas commented 2 years ago

You can create a PR, or just fork the project and show it here. I like the idea. Could be complex though, esp with event management.

Thats what I did:

This is the commit containing the changes on my fork:

https://github.com/janscas/arcade/commit/c3e6268908168d5e9fa3da949027ea9c6634b738

einarf commented 2 years ago

I like this. It can make the code a lot more organized.

It would be nice with a working example using sections in the examples directory that also handles resizing with at least one fixed size and another floating size section.

alejcas commented 2 years ago

I can do that. Resizing can be tricky, but also very powerful, like having “sticky” menus or panels. I’m implementing a more powerful prevent_dispatch and then will work on that.

einarf commented 2 years ago

Resize it a bit tricky yes. There are two modes of resizing:

1) Expand the viewable area keeping projection and viewport the same 2) Zoom up all the content preserving all existing sizes

I think 1) is what most people are looking for and also how we handle resizing by default in arcade. It definitely needs to be something overridable because people will need that.

alejcas commented 2 years ago

@einarf How should I reorganize imports in __init__? I keep getting circular imports.

I just moved the Camera and Section import just before any application Also in camera.py I annotate arcade.Window with a string to avoid circular imports

# inside arcade.__init__
# ...
from .window_commands import unschedule

from .camera import Camera
from .sections import Section, SectionManager

from .application import MOUSE_BUTTON_LEFT
from .application import MOUSE_BUTTON_MIDDLE
from .application import MOUSE_BUTTON_RIGHT
from .application import NoOpenGLException
from .application import View
from .application import Window
# ...

Is this reorganization somehow problematic to you?

alejcas commented 2 years ago

It would be nice with a working example using sections in the examples directory that also handles resizing with at least one fixed size and another floating size section.

Done! check the last commit (https://github.com/pythonarcade/arcade/pull/1072/commits/34addba27be2e4305acb67591f2b5bf33cb46ab7) to PR #1072.

The example is simple... but it can be further enhanced to show the whole Section capabilities (camera automation, plug and unplug sections into views, etc.)

alejcas commented 2 years ago

After a few commits I think Sections base features are complete:

pvcraven commented 2 years ago

Awesome! I'll review.

einarf commented 2 years ago

Released.