Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Issue with pointer events on screen elements #2902

Merged
merged 2 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

-
- Fixed issue where pointer events did not work properly when using [[ScreenElement]]s
- Fixed issue where debug draw was not accurate when using *AndFill suffixed [[DisplayMode]]s

### Updates

Expand Down
28 changes: 27 additions & 1 deletion sandbox/tests/pointer/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ class Player extends ex.Actor {

class Game2 extends ex.Engine {
initialize() {
const screenElement = new ex.ScreenElement({
x: 100,
y: 100,
height: 50,
width: 100,
color: ex.Color.Red
});
screenElement.pointer.useColliderShape = true;
screenElement.pointer.useGraphicsBounds = true;
screenElement.on('pointerdown', () => {
console.log('screen element down')
});
screenElement.on('pointerup', () => {
console.log('screen element up')
});
this.add(screenElement);


const player1 = new Player(ex.Color.Green);
this.add(player1);
player1.z = 10;
Expand Down Expand Up @@ -44,6 +62,14 @@ class Game2 extends ex.Engine {
this.start(loader);
}
}
var game2 = new Game2({width: 600, height: 400});
var game2 = new Game2({
width: 600,
height: 400,
antialiasing: false,
displayMode: ex.DisplayMode.FitScreenAndFill
});
game2.debug.collider.showBounds = true;
game2.debug.graphics.showBounds = true;
game2.toggleDebug();

game2.initialize();
2 changes: 1 addition & 1 deletion src/engine/Camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ export class Camera implements CanUpdate, CanInitialize {
}

public updateViewport() {
// recalc viewport
// recalculate viewport
this._viewport = new BoundingBox(
this.x - this._halfWidth,
this.y - this._halfHeight,
Expand Down
6 changes: 6 additions & 0 deletions src/engine/Debug/DebugSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export class DebugSystem extends System {
this._pushCameraTransform(tx);

this._graphicsContext.save();
if (tx.coordPlane === CoordPlane.Screen) {
this._graphicsContext.translate(this._engine.screen.contentArea.left, this._engine.screen.contentArea.top);
}
this._graphicsContext.z = txSettings.debugZIndex;

this._applyTransform(entity);
Expand Down Expand Up @@ -194,6 +197,9 @@ export class DebugSystem extends System {

// World space
this._graphicsContext.save();
if (tx.coordPlane === CoordPlane.Screen) {
this._graphicsContext.translate(this._engine.screen.contentArea.left, this._engine.screen.contentArea.top);
}
this._graphicsContext.z = txSettings.debugZIndex;
motion = entity.get(MotionComponent);
if (motion) {
Expand Down
28 changes: 24 additions & 4 deletions src/engine/Graphics/GraphicsComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BoundingBox } from '../Collision/Index';
import { Component } from '../EntityComponentSystem/Component';
import { Material } from './Context/material';
import { Logger } from '../Util/Log';
import { WatchVector } from '../Math/watch-vector';

/**
* Type guard for checking if a Graphic HasTick (used for graphics that change over time like animations)
Expand Down Expand Up @@ -79,8 +80,6 @@ export class GraphicsComponent extends Component {

public material: Material | null = null;



/**
* Draws after the entity transform has been applied, but before graphics component graphics have been drawn
*/
Expand Down Expand Up @@ -111,15 +110,36 @@ export class GraphicsComponent extends Component {
*/
public opacity: number = 1;


private _offset: Vector = Vector.Zero;

/**
* Offset to apply to graphics by default
*/
public offset: Vector = Vector.Zero;
public get offset(): Vector {
return new WatchVector(this._offset, () => {
this.recalculateBounds();
});
}
public set offset(value: Vector) {
this._offset = value;
this.recalculateBounds();
}

private _anchor: Vector = Vector.Half;

/**
* Anchor to apply to graphics by default
*/
public anchor: Vector = Vector.Half;
public get anchor(): Vector {
return new WatchVector(this._anchor, () => {
this.recalculateBounds();
});
}
public set anchor(value: Vector) {
this._anchor = value;
this.recalculateBounds();
}

/**
* Flip all graphics horizontally along the y-axis
Expand Down
11 changes: 10 additions & 1 deletion src/engine/Screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ export class Screen {
* Excalibur screen space.
*
* Excalibur screen space starts at the top left (0, 0) corner of the viewport, and extends to the
* bottom right corner (resolutionX, resolutionY)
* bottom right corner (resolutionX, resolutionY). When using *AndFill suffixed display modes screen space
* (0, 0) is the top left of the safe content area bounding box not the viewport.
* @param point
*/
public pageToScreenCoordinates(point: Vector): Vector {
Expand Down Expand Up @@ -575,6 +576,10 @@ export class Screen {
newX = (newX / this.viewport.width) * this.resolution.width;
newY = (newY / this.viewport.height) * this.resolution.height;

// offset by content area
newX = newX - this.contentArea.left;
newY = newY - this.contentArea.top;

return new Vector(newX, newY);
}

Expand All @@ -590,6 +595,10 @@ export class Screen {
let newX = point.x;
let newY = point.y;

// offset by content area
newX = newX + this.contentArea.left;
newY = newY + this.contentArea.top;

newX = (newX / this.resolution.width) * this.viewport.width;
newY = (newY / this.resolution.height) * this.viewport.height;

Expand Down
6 changes: 3 additions & 3 deletions src/spec/ActorSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ describe('A game actor', () => {
it('should have constructor anchor set on graphics component', () => {
const actor = new ex.Actor({anchor: ex.vec(.7, .7)});

expect(actor.anchor).toEqual(ex.vec(.7, .7));
expect(actor.graphics.anchor).toEqual(ex.vec(.7, .7));
expect(actor.anchor).toBeVector(ex.vec(.7, .7));
expect(actor.graphics.anchor).toBeVector(ex.vec(.7, .7));

actor.anchor = ex.vec(0, 0);
expect(actor.graphics.anchor).toEqual(ex.vec(0, 0));
expect(actor.graphics.anchor).toBeVector(ex.vec(0, 0));
});

it('will inherit the scene from the parent entity after being added', () => {
Expand Down
36 changes: 36 additions & 0 deletions src/spec/PointerInputSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,42 @@ describe('A pointer', () => {
expect(actualOrder).toEqual(['actor4', 'actor3', 'actor2', 'actor1']);
});

it('should dispatch point events on screen elements', () => {
const pointerDownSpy = jasmine.createSpy('pointerdown');
const screenElement = new ex.ScreenElement({
x: 50,
y: 50,
width: 100,
height: 100,
color: ex.Color.Red
});
screenElement.on('pointerdown', pointerDownSpy);

engine.add(screenElement);

executeMouseEvent('pointerdown', <any>document, null, 50, 50);
executeMouseEvent('pointerdown', <any>document, null, 50, 150);
executeMouseEvent('pointerdown', <any>document, null, 150, 50);
executeMouseEvent('pointerdown', <any>document, null, 150, 150);
executeMouseEvent('pointerdown', <any>document, null, 100, 100);

engine.currentScene.update(engine, 0);

expect(pointerDownSpy).toHaveBeenCalledTimes(5);

pointerDownSpy.calls.reset();

executeMouseEvent('pointerdown', <any>document, null, 49, 49);
executeMouseEvent('pointerdown', <any>document, null, 49, 151);
executeMouseEvent('pointerdown', <any>document, null, 151, 49);
executeMouseEvent('pointerdown', <any>document, null, 151, 151);

engine.currentScene.update(engine, 0);

expect(pointerDownSpy).toHaveBeenCalledTimes(0);

});

it('can have pointer event canceled', () => {
const actualOrder = [];

Expand Down