LibGDX的事件处理

1.Gdx的事件处理

在LibGDX中,用户输入的捕获不需要我们去实现,框架已经给我们提供了一个Gdx.input静态实例,我们需要做的是设置一个输入处理器。所谓的输入处理器,其实是一种实现了InputProcessor 接口的类。我们可以通过下面的代码来设置:

Gdx.input.setInputProcessor(InputProcessor processor);//设置输入处理器

 

2.事件的分发

我们知道,在使用LibGDX框架进行开发时,我们通常使用Screen + Stage +Actor 的设计方法来制作一个项目。例如我最近在写的一个项目的包结构:

 

 

                                            

 

 

在这种情况下,我们使用Stage的实例作为输入处理器。

Gdx.input.setInputProcessor(stage);//将stage设置为输入处理器

在LibGDX中的事件的监听处理是 分发 的。这一点怎么理解呢?

我们假设将事件的处理器设置为某一个stage实例。那么并不是所有的事件监听和处理都是必须要添加到stage的。

stage作为一个Actor的容器(其内部实际上是封装了一个Group作为Actor的容器),管理着很多的Actor。我们可以给每个Actor实例在需要的情况下addListener(new EventListener()) 。

stge在收到输入事件时,不仅自身的输入监听会起到作用,其内部Actor身上注册的事件监听也会起到作用。这就是所谓的事件的分发。

 

3.引入InputMultiplexer

事件的分发是基于一个输入处理器的,也就是InputProcessor。我们可能会碰到这么一种情况,项目的事件处理器不止一个。拿Stage来说,我们可能会遇到有多个Stage的情况,而此时每个Stage都需要作为事件的处理器注册到Gdx.input输入中。

在这种情况下,我们会发现,每次进行设置,都会讲前面的设置覆盖掉。比如我有一个gameStage和一个helpStage,如果使用以下方式设置:

Gdx.input.setInputProcessor(gameStage);//将gameStage设置为输入处理器
Gdx.input.setInputProcessor(helpStage);//将helpStage设置为输入处理器,此时gameStage'被覆盖掉

我们会发现,第一次的设置不起作用了,实际上是第二次的设置把第一次的设置覆盖更新了。这说明,我们的输入处理器只能设置一个的。在这种情况下,我们的InputMultiplexer就有作用了。

InputMultiplexer inputMultiplexer= new InputMultiplexer();//创建一个InputMultiplexer实例
Gdx.input.setInputProcessor(inputMultiplexer);//将inputMultiplexer设置为输入处理器
inputMultiplexer.addProcessor(gameStage);//添加一个输入处理器gameStage
inputMultiplexer.addProcessor(helpStage);//添加一个输入处理器helpStage

  使用这种方法,我们就可以将两个输入处理器都注册到Gdx中了。

4.深入InputMultiplexer

我们刚刚说过事件的分发,InputMultiplexer在内部是这样实现的,我们来看一下它的源码:

 

//源码
public
void addProcessor (InputProcessor processor) { if (processor == null) throw new NullPointerException("processor cannot be null"); processors.add(processor); }

很简单对吧,其内部维护了一个 Array<InputProcessor> processors ,通过它把所接收到的事件分发给每一个输入处理器。

 5.关于EventListener

  在事件处理器接收到输入的事件之后,会将输入转化成转换成不同的具体事件,然后调用相应的事件监听接口EventListener的实现类。

  其常用实现类有:
(1)InputListener: 输入监听器,包括触屏、 鼠标点击、 键盘按键 的输入。
  keyDown(): 键盘按键按下时被调用
  keyUp(): 键盘按键弹起时被调用
  touchDown(): 触摸屏幕,手指/鼠标按下时被调用
  touchDragged(): 触摸屏幕,手指/鼠标按下后在屏幕上拖动时被调用
  touchUp(): 触摸屏幕,手指/鼠标按下后抬起时被调用
(2)ClickListener: 点击监听器,通常用于舞台/演员被点击的事件监听。只有通过一个完整的按下+抬起 才能触发点击事件。
  clicked(): 当注册监听的对象(舞台/演员)被点击时调用。
 

  5.1 touchDown()方法的理解

//源码
public
boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { return false; }

 

          该方法在被手指/鼠标 按下时调用。
         
          @param x :  按下时的 X 轴坐标, 相对于被触摸对象(监听器注册者)的左下角
          
          @param y :  按下时的 Y 轴坐标, 相对于被触摸对象(监听器注册者)的左下角
         
          @param pointer :
               按下手指的ID, 用于多点触控时辨别按下的是第几个手指,
               一般情况下第一只手指按下时 pointer 为 0, 手指未抬起前又有一只手指按下, 则后按下的手指 pointer 为 1。
               同一只手指的 按下(touchDown), 拖动(touchDragged), 抬起(touchUp)属于同一次序列动作(pointer 值相同),
               pointer 的值在 按下 时被确定, 之后这只手指产生的的 拖动 和 抬起 动作将会把该已确定的 pointer 值传递给其事件方法
               touchDragged() 和 touchUp() 方法。
          
        @return :  返回值为 boolean 类型, 用于告诉上一级当前对象(演员/舞台)是否需要处理该次事件。 
               返回 true: 表示当前对象需要处理该次事件, 则之后这只手指产生的 拖动(touchDragged)和 抬起(touchUp)事件也会传递到当前对象。
               返回 false: 表示当前对象不处理该次事件, 既然不处理, 则之后这只手指产生的 拖动(touchDragged)和 抬起(touchUp)事件也将不会再传到到当前对象。

              PS: 当前对象是否处理一只手指的触摸事件(按下, 拖动, 抬起)只在 按下时(touchDown)确定,所以之后的 touchDragged() 和 touchUp() 方法中就不再判断, 因此返回类型为 void。
         

 

 

 

 

 

 

posted @ 2020-07-27 15:33  远有多远  阅读(414)  评论(0)    收藏  举报