Libgdx中事件传递过程解析
博客专区 > asay 的博客 > 博客详情
Libgdx中事件传递过程解析
asay 发表于1年前
Libgdx中事件传递过程解析
  • 发表于 1年前
  • 阅读 18
  • 收藏 0
  • 点赞 0
  • 评论 0

【腾讯云】新注册用户域名抢购1元起>>>   

直接看代码.

先看stage中touchDown()

/** Applies a touch down event to the stage and returns true if an actor in the scene {@link Event#handle() handled} the
	 * event. */
	public boolean touchDown (int screenX, int screenY, int pointer, int button) {
		if (screenX < viewport.getScreenX() || screenX >= viewport.getScreenX() + viewport.getScreenWidth()) return false;
		if (Gdx.graphics.getHeight() - screenY < viewport.getScreenY()
			|| Gdx.graphics.getHeight() - screenY >= viewport.getScreenY() + viewport.getScreenHeight()) return false;

		pointerTouched[pointer] = true;
		pointerScreenX[pointer] = screenX;
		pointerScreenY[pointer] = screenY;

		screenToStageCoordinates(tempCoords.set(screenX, screenY));

		InputEvent event = Pools.obtain(InputEvent.class);
		event.setType(Type.touchDown);
		event.setStage(this);
		event.setStageX(tempCoords.x);
		event.setStageY(tempCoords.y);
		event.setPointer(pointer);
		event.setButton(button);

		Actor target = hit(tempCoords.x, tempCoords.y, true);
		if (target == null) {
			if (root.getTouchable() == Touchable.enabled) root.fire(event);
		} else {
			target.fire(event);
		}

		boolean handled = event.isHandled();
		Pools.free(event);
		return handled;
	}

 

在看Actor 中的fire()

/** Sets this actor as the event {@link Event#setTarget(Actor) target} and propagates the event to this actor and ancestor
	 * actors as necessary. If this actor is not in the stage, the stage must be set before calling this method.
	 * <p>
	 * Events are fired in 2 phases:
	 * <ol>
	 * <li>The first phase (the "capture" phase) notifies listeners on each actor starting at the root and propagating downward to
	 * (and including) this actor.</li>
	 * <li>The second phase notifies listeners on each actor starting at this actor and, if {@link Event#getBubbles()} is true,
	 * propagating upward to the root.</li>
	 * </ol>
	 * If the event is {@link Event#stop() stopped} at any time, it will not propagate to the next actor.
	 * @return true if the event was {@link Event#cancel() cancelled}. */
	public boolean fire (Event event) {
		if (event.getStage() == null) event.setStage(getStage());
		event.setTarget(this);

		// Collect ancestors so event propagation is unaffected by hierarchy changes.
		Array<Group> ancestors = Pools.obtain(Array.class);
		Group parent = this.parent;
		while (parent != null) {
			ancestors.add(parent);
			parent = parent.parent;
		}

		try {
			// Notify all parent capture listeners, starting at the root. Ancestors may stop an event before children receive it.
			Object[] ancestorsArray = ancestors.items;
			for (int i = ancestors.size - 1; i >= 0; i--) {
				Group currentTarget = (Group)ancestorsArray[i];
				currentTarget.notify(event, true);
				if (event.isStopped()) return event.isCancelled();
			}

			// Notify the target capture listeners.
			notify(event, true);
			if (event.isStopped()) return event.isCancelled();

			// Notify the target listeners.
			notify(event, false);
			if (!event.getBubbles()) return event.isCancelled();
			if (event.isStopped()) return event.isCancelled();

			// Notify all parent listeners, starting at the target. Children may stop an event before ancestors receive it.
			for (int i = 0, n = ancestors.size; i < n; i++) {
				((Group)ancestorsArray[i]).notify(event, false);
				if (event.isStopped()) return event.isCancelled();
			}

			return event.isCancelled();
		} finally {
			ancestors.clear();
			Pools.free(ancestors);
		}
	}

 

好吧,仔细看可以看清楚流程.但是我想用直白的语言总结一下.

在stage中hit() 只会选出一个actor作为此次点击的目标target.

然后这个actor调用fire(),在通知中有4个过程:

1.在捕获阶段,通知各个父节点的capture listeners,从最根部的节点开始.

2.再通知自己的capture listeners.

3.然后到了通知阶段,先通知自己的target listeners.

4.最后通知父节点的target listeners,从最近的节点开始.

此过程看明白以后,在游戏中控制事件Event就可以非常的灵活.

private boolean capture; // true means event occurred during the capture phase
private boolean bubbles = true; // true means propagate to target's parents
private boolean handled; // true means the event was handled (the stage will eat the input)
private boolean stopped; // true means event propagation was stopped
private boolean cancelled; // true means propagation was stopped and any action that this event would cause should not happen

补充:

1.capture 字段的意义:在自定义的Listeners中判断处于什么阶段是根据isCapture()判断的,所以在自定义的Listeners中禁止调用setCapture().

2.stoped 字段的意义:在上面4个过程中,随时想停止都可以调用stop() 或者 cancel() 来停止后面的过程.

3.bubbles 字段的意义:如果在前3个过程中,不想经历第4个过程,可以setBubbles(false).

4.handled 字段的意义:是针对多个InputProcessor及使用了InputMultiplexer的情况,如果handled为true,后面的InputProcessor就不再处理了.只有handled为false,后面的才会处理.

标签: libgdx
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 0
博文 14
码字总数 5272
×
asay
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: