直接看代码.
先看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,后面的才会处理.