Skip to content

Commit

Permalink
refactor: Pointer System refactor (#2071)
Browse files Browse the repository at this point in the history
This is still work in progress, the goal is for this to be nearly 100% backwards compatible
- [x] Re-implement missing API surface
- [x] Remove old pointer system
- [x] Fix tests


Related #1161 Pointer Refactor

## Changes:

- Refactors pointer system into ECS style system
- Pointer component allows for configuring
- Will add the ability to use the collider and or the graphics as the target for pointer events
  • Loading branch information
eonarheim authored Nov 10, 2021
1 parent 659ecc2 commit bc7986b
Show file tree
Hide file tree
Showing 38 changed files with 1,175 additions and 1,615 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"jsdoc/require-returns": 0,
"jsdoc/require-returns-type": 0,
"jsdoc/newline-after-description": 0,
"jsdoc/no-multi-asterisks": 0,
"jsdoc/check-tag-names": ["error", { "definedTags": ["hidden", "internal", "source", "obsolete", "warning", "notimplemented", "credit", "typedoc"]}]
}
}
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Pointers can now be configured to use the collider or the graphics bounds as the target for pointers with the `ex.PointerComponent`
- `useColliderShape` - (default true) uses the collider component geometry for pointer events
- `useGraphicsBounds` - (default false) uses the graphics bounds for pointer events
-

### Fixed
Expand All @@ -27,6 +30,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Pointer Events:
* Event types (up, down, move, etc) now all exist in 2 types `ex.Input.PointerEvent` and `ex.Input.WheelEvent`
* The `stopPropagation()` method used to cancel further dispatches has been renamed to `cancel()` to match other events API.
* Events no longer have a reference to the `pointer` but now have all of the same information that was availabe on the pointer `worldPos`, `screenPos`, `pagePos`
-

<!--------------------------------- DO NOT EDIT BELOW THIS LINE --------------------------------->
Expand All @@ -42,9 +49,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Story to show a play / pause implementation.
- `ex.Animation` now support `totalDuration` that will calculate automatically each frame duration based on how many frames have.
- `ex.Animation` now supports `.reverse()` to reverse the direction of play in an animation, use the `ex.Animation.direction` to inspect if the animation is playing in the `ex.AnimationDirection.Forward` direction or the `ex.AnimationDirection.Backward` direction.

### Changed

- Pointer system refactored into 2 parts:
* First is an ECS style system `ex.PointerSystem` that dispatches events to Entities/Actors
* Second is an event receiver `ex.PointerEventReceiver` which is responsible for collecting the native browser events
* The API is mostly backwards compatible breaking changes are listed in the breaking change section, event types have been simplified, and `stopPropagation()` and been renamed to `cancel()`
- Internal Actions implementation converted to ECS system and component, this is a backwards compatible change with v0.25.0
- `ex.ActionsSystem` and `ex.ActionsComponent` now wrap the existing `ex.ActionContext`
- Actions can be shared with all entities now!
Expand Down
22 changes: 20 additions & 2 deletions sandbox/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,25 @@ game.input.keyboard.on('up', (e?: ex.Input.KeyEvent) => {
});

player.on('pointerdown', (e?: ex.Input.PointerEvent) => {
alert('Player clicked!');
// alert('Player clicked!');
});
player.on('pointerdown', () => {
console.log('pointer down');
});
player.on('pointerup', () => {
console.log('pointer up');
});
player.on('pointermove', () => {
//console.log('pointer over');
});
player.on('pointerleave', () => {
console.log('pointer exit');
});
player.on('pointerenter', () => {
console.log('pointer enter');
});
player.on('pointerwheel', () => {
console.log('pointer wheel');
});

var newScene = new ex.Scene();
Expand Down Expand Up @@ -820,7 +838,7 @@ var trigger = new ex.Trigger({

game.add(trigger);

game.input.pointers.primary.on('down', (evt?: ex.Input.PointerEvent) => {
game.input.pointers.primary.on('down', (evt: ex.Input.PointerEvent) => {
var c = tileMap.getCellByPoint(evt.worldPos.x, evt.worldPos.y);
if (c) {
if (c.solid) {
Expand Down
4 changes: 2 additions & 2 deletions sandbox/tests/boundingbox/bbtester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ block2.on('pointerdragend', (pe: ex.Input.PointerEvent) => {
// Drag box around
block2.on('pointerdragmove', (pe: ex.Input.PointerEvent) => {
if (boxPointerDragging) {
block2.pos = pe.pointer.lastWorldPos;
block2.pos = pe.worldPos;
}
});

// Drag box around
block2.on('pointerdragleave', (pe: ex.Input.PointerEvent) => {
if (boxPointerDragging) {
block2.pos = pe.pointer.lastWorldPos;
block2.pos = pe.worldPos;
}
});

Expand Down
8 changes: 4 additions & 4 deletions sandbox/tests/input/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ box.on('pointerdown', (pe: ex.Input.PointerEvent) => {

box2.on('pointerdown', (pe: ex.Input.PointerEvent) => {
console.log('box2 clicked');
pe.stopPropagation();
pe.cancel();
if (box2.color.toString() === ex.Color.White.toString()) {
box2.color = ex.Color.Yellow;
} else {
Expand All @@ -52,14 +52,14 @@ box.on('pointerdragend', (pe: ex.Input.PointerEvent) => {
// Drag box around
box.on('pointerdragmove', (pe: ex.Input.PointerEvent) => {
if (boxPointerDragging) {
box.pos = pe.pointer.lastWorldPos;
box.pos = pe.worldPos;
}
});

// Drag box around
box.on('pointerdragleave', (pe: ex.Input.PointerEvent) => {
if (boxPointerDragging) {
box.pos = pe.pointer.lastWorldPos;
box.pos = pe.worldPos;
}
});

Expand All @@ -69,7 +69,7 @@ box.on('pointerwheel', (pe: ex.Input.WheelEvent) => {

// Follow cursor
game.input.pointers.primary.on('move', (pe: ex.Input.PointerEvent) => {
cursor.pos = pe.pointer.lastWorldPos;
cursor.pos = pe.worldPos;
});

// Button type
Expand Down
2 changes: 1 addition & 1 deletion sandbox/tests/physics/physics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ game.input.keyboard.on('down', (evt: ex.Input.KeyEvent) => {
}
});

game.input.pointers.primary.on('down', (evt: ex.Input.PointerDownEvent) => {
game.input.pointers.primary.on('down', (evt: ex.Input.PointerEvent) => {
spawnBlock(evt.worldPos.x, evt.worldPos.y);
});

Expand Down
114 changes: 30 additions & 84 deletions src/engine/Actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
EnterViewPortEvent,
ExitViewPortEvent
} from './Events';
import { PointerEvent, WheelEvent, PointerDragEvent, PointerEventName } from './Input/PointerEvents';
import { Engine } from './Engine';
import { Color } from './Color';
import { Sprite } from './Drawing/Sprite';
Expand Down Expand Up @@ -51,7 +50,9 @@ import { Shape } from './Collision/Colliders/Shape';
import { watch } from './Util/Watch';
import { Collider, CollisionGroup } from './Collision/Index';
import { Circle } from './Graphics/Circle';
import { CapturePointerConfig } from './Input/CapturePointerConfig';
import { PointerEvent } from './Input/PointerEvent';
import { WheelEvent } from './Input/WheelEvent';
import { PointerComponent } from './Input/PointerComponent';
import { ActionsComponent } from './Actions/ActionsComponent';

/**
Expand Down Expand Up @@ -197,6 +198,13 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
return this.get(ColliderComponent);
}

/**
* Access to the Actor's built in [[PointerComponent]] config
*/
public get pointer(): PointerComponent {
return this.get(PointerComponent);
}

/**
* Useful for quickly scripting actor behavior, like moving to a place, patroling back and forth, blinking, etc.
*
Expand Down Expand Up @@ -427,13 +435,13 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia

private _pointerDragMoveHandler = (pe: PointerEvent) => {
if (this._dragging) {
this.pos = pe.pointer.lastWorldPos;
this.pos = pe.worldPos;
}
};

private _pointerDragLeaveHandler = (pe: PointerEvent) => {
if (this._dragging) {
this.pos = pe.pointer.lastWorldPos;
this.pos = pe.worldPos;
}
};

Expand Down Expand Up @@ -461,6 +469,7 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia

/**
* Modify the current actor update pipeline.
* @deprecated will be removed in v0.26.0
*/
public traits: Trait[] = [];

Expand All @@ -478,20 +487,6 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
}
private _color: Color;

/**
* Whether or not to enable the [[Traits.CapturePointer]] trait that propagates
* pointer events to this actor
*/
public enableCapturePointer: boolean = false;

/**
* Configuration for [[Traits.CapturePointer]] trait
*/
public capturePointer: CapturePointerConfig = {
captureMoveEvents: false,
captureDragEvents: false
};

// #endregion

/**
Expand Down Expand Up @@ -534,6 +529,8 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
this.scale = scale ?? vec(1, 1);
this.z = z ?? 0;

this.addComponent(new PointerComponent);

this.addComponent(new GraphicsComponent());
this.addComponent(new CanvasDrawComponent((ctx, delta) => this.draw(ctx, delta)));
this.addComponent(new MotionComponent());
Expand Down Expand Up @@ -588,7 +585,6 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
// TODO remove offscreen trait after legacy drawing removed
this.traits.push(new Traits.OffscreenCulling());
}
this.traits.push(new Traits.CapturePointer());

}

Expand Down Expand Up @@ -618,54 +614,6 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia

// #region Events

private _capturePointerEvents: PointerEventName[] = [
'pointerup',
'pointerdown',
'pointermove',
'pointerenter',
'pointerleave',
'pointerdragstart',
'pointerdragend',
'pointerdragmove',
'pointerdragenter',
'pointerdragleave'
];

private _captureMoveEvents: PointerEventName[] = [
'pointermove',
'pointerenter',
'pointerleave',
'pointerdragmove',
'pointerdragenter',
'pointerdragleave'
];

private _captureDragEvents: PointerEventName[] = [
'pointerdragstart',
'pointerdragend',
'pointerdragmove',
'pointerdragenter',
'pointerdragleave'
];

private _checkForPointerOptIn(eventName: string) {
if (eventName) {
const normalized = <PointerEventName>eventName.toLowerCase();

if (this._capturePointerEvents.indexOf(normalized) !== -1) {
this.enableCapturePointer = true;

if (this._captureMoveEvents.indexOf(normalized) !== -1) {
this.capturePointer.captureMoveEvents = true;
}

if (this._captureDragEvents.indexOf(normalized) !== -1) {
this.capturePointer.captureDragEvents = true;
}
}
}
}

public on(eventName: Events.exittrigger, handler: (event: ExitTriggerEvent) => void): void;
public on(eventName: Events.entertrigger, handler: (event: EnterTriggerEvent) => void): void;
/**
Expand Down Expand Up @@ -720,16 +668,15 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
public on(eventName: Events.pointermove, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointercancel, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointerwheel, handler: (event: WheelEvent) => void): void;
public on(eventName: Events.pointerdragstart, handler: (event: PointerDragEvent) => void): void;
public on(eventName: Events.pointerdragend, handler: (event: PointerDragEvent) => void): void;
public on(eventName: Events.pointerdragenter, handler: (event: PointerDragEvent) => void): void;
public on(eventName: Events.pointerdragleave, handler: (event: PointerDragEvent) => void): void;
public on(eventName: Events.pointerdragmove, handler: (event: PointerDragEvent) => void): void;
public on(eventName: Events.pointerdragstart, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointerdragend, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointerdragenter, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointerdragleave, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.pointerdragmove, handler: (event: PointerEvent) => void): void;
public on(eventName: Events.enterviewport, handler: (event: EnterViewPortEvent) => void): void;
public on(eventName: Events.exitviewport, handler: (event: ExitViewPortEvent) => void): void;
public on(eventName: string, handler: (event: GameEvent<Actor>) => void): void;
public on(eventName: string, handler: (event: any) => void): void {
this._checkForPointerOptIn(eventName);
super.on(eventName, handler);
}

Expand Down Expand Up @@ -787,16 +734,15 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
public once(eventName: Events.pointermove, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointercancel, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointerwheel, handler: (event: WheelEvent) => void): void;
public once(eventName: Events.pointerdragstart, handler: (event: PointerDragEvent) => void): void;
public once(eventName: Events.pointerdragend, handler: (event: PointerDragEvent) => void): void;
public once(eventName: Events.pointerdragenter, handler: (event: PointerDragEvent) => void): void;
public once(eventName: Events.pointerdragleave, handler: (event: PointerDragEvent) => void): void;
public once(eventName: Events.pointerdragmove, handler: (event: PointerDragEvent) => void): void;
public once(eventName: Events.pointerdragstart, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointerdragend, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointerdragenter, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointerdragleave, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.pointerdragmove, handler: (event: PointerEvent) => void): void;
public once(eventName: Events.enterviewport, handler: (event: EnterViewPortEvent) => void): void;
public once(eventName: Events.exitviewport, handler: (event: ExitViewPortEvent) => void): void;
public once(eventName: string, handler: (event: GameEvent<Actor>) => void): void;
public once(eventName: string, handler: (event: any) => void): void {
this._checkForPointerOptIn(eventName);
super.once(eventName, handler);
}

Expand Down Expand Up @@ -844,11 +790,11 @@ export class Actor extends Entity implements Eventable, PointerEvents, CanInitia
public off(eventName: Events.pointermove, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointercancel, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointerwheel, handler?: (event: WheelEvent) => void): void;
public off(eventName: Events.pointerdragstart, handler?: (event: PointerDragEvent) => void): void;
public off(eventName: Events.pointerdragend, handler?: (event: PointerDragEvent) => void): void;
public off(eventName: Events.pointerdragenter, handler?: (event: PointerDragEvent) => void): void;
public off(eventName: Events.pointerdragleave, handler?: (event: PointerDragEvent) => void): void;
public off(eventName: Events.pointerdragmove, handler?: (event: PointerDragEvent) => void): void;
public off(eventName: Events.pointerdragstart, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointerdragend, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointerdragenter, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointerdragleave, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.pointerdragmove, handler?: (event: PointerEvent) => void): void;
public off(eventName: Events.prekill, handler?: (event: PreKillEvent) => void): void;
public off(eventName: Events.postkill, handler?: (event: PostKillEvent) => void): void;
public off(eventName: Events.initialize, handler?: (event: Events.InitializeEvent<Actor>) => void): void;
Expand Down
9 changes: 4 additions & 5 deletions src/engine/Class.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { GameEvent } from './Events';
import { EventDispatcher } from './EventDispatcher';
import { Eventable } from './Interfaces/Evented';

Expand All @@ -22,7 +21,7 @@ export class Class implements Eventable {
* @param eventName Name of the event to listen for
* @param handler Event handler for the thrown event
*/
public on(eventName: string, handler: (event: GameEvent<any>) => void) {
public on(eventName: string, handler: (event: any) => void) {
this.eventDispatcher.on(eventName, handler);
}

Expand All @@ -34,7 +33,7 @@ export class Class implements Eventable {
* @param eventName Name of the event to listen for
* @param handler Event handler for the thrown event
*/
public off(eventName: string, handler?: (event: GameEvent<any>) => void) {
public off(eventName: string, handler?: (event: any) => void) {
this.eventDispatcher.off(eventName, handler);
}

Expand All @@ -43,7 +42,7 @@ export class Class implements Eventable {
* @param eventName Name of the event to emit
* @param eventObject Data associated with this event
*/
public emit(eventName: string, eventObject: GameEvent<any>) {
public emit(eventName: string, eventObject: any) {
this.eventDispatcher.emit(eventName, eventObject);
}

Expand All @@ -53,7 +52,7 @@ export class Class implements Eventable {
* @param eventName The name of the event to subscribe to once
* @param handler The handler of the event that will be auto unsubscribed
*/
public once(eventName: string, handler: (event: GameEvent<any>) => void) {
public once(eventName: string, handler: (event: any) => void) {
this.eventDispatcher.once(eventName, handler);
}
}
Loading

0 comments on commit bc7986b

Please sign in to comment.