分段#

在一个简单的游戏中,整个视区都用来显示游戏的“地图”。在更高级的游戏中,将此视口分成不同的“部分”并使用不同的用法是很正常的。显示和处理不同信息的区域。例如,你可以在顶部有一个菜单,在右边有一些信息面板,游戏主“屏幕”(“地图”)覆盖了视区的其余部分。

为了实现这种游戏逻辑的分离,您需要使用几个部分。一个 Section 是一种将一个 View 将空间分成更小的部分,然后每个部分将根据配置和占用的视图空间接收重定向的事件。节可以隔离原本打包在一起的代码 View 。这样,代码就会保持在它所属的位置,而不会与程序的其他部分的代码混合在一起。

通过配置 Section 您可以捕获某些事件,或者例如仅捕获键盘事件中的某些键。您还可以配置将哪些事件传播到其他底层部分,甚至传播到视图本身。

部分也可以是“模式”的,这意味着它们将首先捕获所有事件,但最后绘制,并且还将阻止其他视图接收 on_update 事件。

还要注意的是,如果在代码中不使用节,则不会发生任何变化。即使是 SectionManager 如果不添加横断面,则不会创建。

Key features of Sections:

  • 将屏幕划分为逻辑组件(部分)。

  • 事件调度:A Section 将根据视图中占用的空间来捕获鼠标事件。此外,还将根据配置捕获键盘事件。

  • 阻止派单:A Section 可以配置为防止调度捕获的事件或让事件流向下面的其他部分。

  • 事件捕获顺序:基于 Section 插入顺序您可以配置节捕获事件的顺序。

  • 绘制顺序:您可以配置绘制部分的顺序(部分可以重叠!)。

  • Section “Enable”属性以显示或隐藏节。你可以用谷歌搜索这个。

  • 模态节:最后绘制但捕获所有事件并阻止其他节更新的节。

  • 自动相机切换:当在不同的分区之间切换时,分区将尝试激活和停用摄像头。

Important: You don't need to cover 100% of the View with sections. Sections can work with the View as well. Also, Sections can overlap.

一个简单的例子#

没有使用节的小程序需要在 on_mouse_release 事件根据鼠标位置知道要执行的操作。

例如,如果鼠标位于地图的顶部,您可能想要执行某些操作,但如果鼠标位于其他位置,则可能需要执行其他操作。

这就是在不考虑部分的情况下的情况:

class MyView(arcade.View):
    # ...

    def on_mouse_release(x: int, y: int, *args, **kwargs):
        if x > 700:
            # click in the side
            do_some_logic_when_side_clicking()
        else:
            # click on the game map
            do_something_in_the_game_map()

这段代码可能并且经常变得很长,并且需要进行大量检查才能知道要做什么。

通过使用节,您可以改进此代码并自动执行此简单检查。

下面是使用小节时的样子:

class Map(arcade.Section):

    # ...

    def on_mouse_release(x: int, y: int, *args, **kwargs):
        # clicks on the map are handled here
        pass


class Side(arcade.Section):

    # ...

    def on_mouse_release(x: int, y: int, *args, **kwargs):
        # clicks on the side of the screen are handled here
        pass


class MyView(arcade.View):

    def __init__(self, *args, **kwargs):
        self.map_section = Map(0, 0, 700, self.window.height)
        self.side_section = SideSpace(700, 0, 100, self.window.height)

        self.add_section(self.map_section)
        self.add_section(self.side_section)

    # ...

如何使用节#

要使用节,您首先需要具有 View 。节视图而定,并由特殊的 SectionManager 内部 View 。别担心,99%的情况下您不需要与 SectionManager

要创建 Section 从继承开始 arcade.Section

基于 Section 配置您的分区将开始从视图接收事件 SectionManager 。一个 Section 是否将所有事件都作为 View 有喜欢的 on_drawon_updateon_mouse_press

实例化时定义节的位置参数(左、下、宽、高)。这些是非常重要的属性 Section :因为他们定义了事件捕获矩形区域。

对象的属性 Section

position: (left, bottom, width, height)

这是实例化 Section 。这一点非常重要,因为此矩形位置将决定鼠标相关事件的事件捕获空间。这也将帮助您确定类内部的空间,例如,当您想要绘制某些东西或计算坐标时。

name:

A Section 可以有选择地获得一个名称,这样就更容易调试和索引What Section正在做什么。例如,当记录时,记录 Section 在开头命名,这样您就可以从生成日志的位置进行引用。

accept_keyboard_keys:

This allows to tell if a Section can receive keyboard events (accept_keyboard_keys=False) or to tell which keyboard keys are captured in this Section (accept_keyboard_keys={arade.key.UP, arcade.key.DOWN})

accept_mouse_events:

This allows to tell if a Section can receive mouse events or which mouse events are accepted. For example: accept_mouse_events={'on_mouse_move'} means only mouse move events will be captured.

prevent_dispatch:

这告诉我们一个 Section 如果它应该阻止将某些事件调度到事件捕获流下游的其他部分。默认情况下, Section 将阻止调度所有已处理的事件。通过路过 prevent_dispatch={'on_mouse_press'} 所有事件都将沿事件捕获流向下传播,但 on_mouse_press 事件。请注意,传球 prevent_dispatch=None (缺省值)与通过 prevent_dispatch={True} 这意味着“阻止所有事件”调度到其他部分。您还可以设置 prevent_dispatch={False} 将所有事件分派到其他部分。

prevent_dispatch_view:

这允许告诉一个 Section 如果不应将事件(以及哪些事件)调度到基础 View 。如果要在中执行某些操作,这将非常方便 View 是否由另一个事件处理的代码 Section 。默认情况下, Section 将阻止将所有已处理的事件调度到 View 。请注意,传球 prevent_dispatch=None (缺省值)与通过 prevent_dispatch={True} 这意味着“阻止所有事件”调度到视图。您还可以设置 prevent_dispatch={False} 将所有事件分派到其他部分。 Also note that in order for the view to receive any event, ALL the sections need to allow the dispatch of that particular event. If at least one section prevents it, the event will not be delivered to the view.

local_mouse_coordinates:

如果为True,则分区鼠标事件将收到与分区尺寸和位置相关的x,y坐标分区(与屏幕无关)。 Note that although this seems very usefull, section local coordinates doesn't work with arcade collision methods. You can use Section ``get_xy_screen_relative`` to transform local mouse coordinates to screen coordinates that work with arcade collision methods

enabled:

默认情况下,启用所有部分。这使我们可以判断这个粒子是否 Section 应启用或未启用。如果一个 Section 未启用,它将不会捕获任何事件、绘制、更新等。它将作为它不存在。您可以随时启用和禁用部分,从而产生一些很酷的效果。请注意,设置此属性将触发该部分 on_show_sectionon_hide_section 事件。

modal:

这将告诉 SectionManager 这件事 Section 是模式化的。这意味着 Section 将首先捕获所有事件,而不向基础部分或视图传递任何事件。此外,它将画在最后(在其他 on_draw 呼叫)。启用模式时 Section 将阻止所有其他分区接收 on_update 事件。

draw_order:

这样就可以定义绘制顺序 Section 会有的。数字越小,这一部分就会越早抽签。当您有重叠的部分并且需要一些时,这是很方便的 Section 画在另一个上面。默认情况下,将按照添加的顺序绘制节段(除了模式节段,无论最后绘制的是什么)。注意,这可以不同于事件捕获顺序或ON_UPDATE顺序,后者由 SectionManager

其他便携设备 Section 属性:

  • BLOCK_UPDATES:如果为True,则该节将不包含 on_update 方法已调用。

  • 摄像机:这是用来装一个 arcade.Camera 但默认情况下,它是没有的。SectionManager会在需要时自动触发摄像头的使用。

很方便 Section :方法:

  • Overlaps_With:这将告诉您另一个 Section 与这张重叠。

  • MICUE_IS_ON_TOP:这将告诉我们,如果给定x,y坐标,则鼠标位于该部分的顶部。

  • Get_xy_Screen_Relative:从x,y部分坐标获取屏幕x,y坐标。

  • GET_XY_SECTION_Relative:从x,y屏幕坐标获取x,y部分坐标。

用一个例子说明配置和逻辑#

想象一个游戏,其中你有这样的基本组件:

  • 800x600屏幕视区

  • 一张游戏地图

  • 屏幕顶部的菜单栏

  • 右侧面板显示游戏中的数据

  • 弹出消息(对话框)

使用此配置,您可以将此逻辑划分为具有某种配置的部分。

让我们看看此配置可能是什么样子:

import arcade


class Map(arcade.Section):
    #... define all the section logic


class Menu(arcade.Section):
    #... define all the section logic


class Panel(arcade.Section):
    #... define all the section logic


class PopUp(arcade.Section):
    def __init__(message, *args, **kwargs):
        super().__init(*args, **kwargs)
        self.message = message

    # define draw logic, etc...


class MyView(arcade.View):

    def __init__(self, *args, **kwargs):
        self.map = Map(left=0, bottom=0, width=600, height=550,
                       name='Map', draw_order=2)
        self.menu = Menu(left=0, bottom=550, width=800, height=50,
                         name='Menu', accept_keyboard_keys=False,
                         accept_mouse_events={'on_mouse_press'})
        self.panel = Panel(left=600, bottom=0, width=200, height=550,
                            name='Panel', accept_keyboard_keys=False,
                            accept_mouse_events=False)

        popup_left = (self.view.window.width // 2) - 200
        popup_bottom = (self.view.window.height // 2) - 100
        popup_width = 400
        popup_height = 200
        self.popup = PopUp(message='', popup_left, popup_bottom, popup_width,
                           popup_height, enabled=False, modal=True)

        self.add_section(self.map)
        self.add_section(self.menu)
        self.add_section(self.panel)
        self.add_section(self.popup)

    def close():
        self.popup.message = 'Are you sure you want to close the view?'
        self.popup.enabled = True

让我们一步一步地走。首先,我们配置一个保存地图的Map部分。此部分将从左侧开始,底部=0,0,并且不会占据整个屏幕。Map事件处理程序不会处理发生在此坐标之外的鼠标事件。因此,Map只需要处理地图内部发生的事情。

其次,我们配置一个包含一些按钮的菜单部分。此菜单占据地图已离开的屏幕顶部空间。地图+菜单将占据100%的屏幕高度。菜单部分配置为不接收任何键盘事件,仅接收ON_MOUSE_PRESS事件,忽略所有其他类型的鼠标事件。

第三,面板也不会接收键盘事件。因此,Map是目前唯一处理键盘事件的工具。此外,面板中不允许发生任何鼠标事件。此面板仅用于显示数据。

对于最后一部分,请注意,我们定义了一个部分,它将首先被禁用,这就是模式。这一部分将呈现带有消息的内容。在调用视图的Close方法时使用该节。因为弹出窗口是一个模式节,当启用它时,它会呈现在所有内容的顶部。此外,所有其他节停止更新,所有事件都由模式节捕获。因此,简而言之,我们是在“阻止”弹出窗口之外的世界。

区段独有事件#

有几个属于部分的独特事件,它们的触发方式有某种特殊之处:

  • on_mouse_enteron_mouse_leave

    这些事件在两种情况下触发:当鼠标进入/离开视图时以及当 SectionManager 通过鼠标移动(或拖动)检测鼠标是否已进入/离开截面尺寸。

  • on_show_sectionon_hide_section

    只有在以下情况下才触发这些事件 is enabled 在某些情况下,必须知道:

    • 在添加节或从 SectionManager 以及 View 目前正在上映

    • 启用或禁用该部分时

    • 当窗口调用时 on_show_viewon_hide_view

科长#

在幕后,当节添加到 View 这个 SectionManager 是将处理所有事件而不是 View 它本身。

您可以访问 SectionManager 通过访问 View.section_manager 。请注意,如果不使用节,则不会使用或创建视图中的节管理器。

通常,您不需要使用 SectionManager ,但在某些情况下,您需要使用它。

您通常使用以下命令来添加部分 View.add_section 但同样的方法也存在于 SectionManager 。此外,您还拥有一个 remove_section 以及一个 clear_sections 方法。

你可以的 enabledisable 这个 SectionManager 一次完全启用或禁用所有部分。

中公开的一些其他功能。 SectionManager 喜欢 get_section_by_name 这也可能是有用的。查看API以了解这些内容。

还可以在中配置三个属性 SectionManager 有时是有用和重要的。

默认情况下, on_drawon_updateon_resize 是将始终在 View 在任何部门触发它们之前。这是默认设置,但您可以使用以下属性对其进行配置:

  • view_draw_first

  • view_update_first

  • view_resize_first

这三种工作方式都是相同的:

  • True(默认值),以在 View 在各部分之前。

  • FALSE,因此它在 View 后各节有相应的方法。

  • 中不触发该事件。 View 完全没有。