Skip to content

Commit

Permalink
fix(pointer): correctly track objects when scene/tileEngine camera is…
Browse files Browse the repository at this point in the history
… moved (#340)
  • Loading branch information
straker authored Jan 26, 2023
1 parent eb57766 commit 39f1d19
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 6 deletions.
31 changes: 25 additions & 6 deletions src/scene.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getContext } from './core.js';
import GameObject from './gameObject.js';
import { GameObjectClass } from './gameObject.js';
import { on, off } from './events.js';
import { srOnlyStyle, addToDom, removeFromArray } from './utils.js';
import { collides } from './helpers.js';
Expand Down Expand Up @@ -156,21 +156,38 @@ class Scene {
section.id = id;
section.setAttribute('aria-label', name);

this.add(objects);

/**
* The camera object which is used as the focal point for the scene. Defaults to to the size of the canvas with a focal point at its center. The scene will not render objects that are outside the bounds of the camera.
*
* Additionally, the camera can be used to [lookAt](api/scene#lookAt) an object which will center the camera to that object. This allows you to zoom the scene in and out while the camera remains centered on the object.
* @memberof Scene
* @property {GameObject} camera
*/
this.camera = GameObject({
let _this = this;
class Camera extends GameObjectClass {
set x(value) {
_this.sx = value - this.centerX;
super.x = value;
}
get x() {
return super.x;
}
set y(value) {
_this.sy = value - this.centerY;
super.y = value;
}
get y() {
return super.y;
}
}
this.camera = new Camera({
context,
anchor: { x: 0.5, y: 0.5 },
render: this._rf.bind(this)
});

this.add(objects);

// i = init
this._i = () => {
this.context ??= getContext();
Expand All @@ -179,12 +196,12 @@ class Scene {
let x = width / 2;
let y = height / 2;
Object.assign(this.camera, {
centerX: x,
centerY: y,
x,
y,
width,
height,
centerX: x,
centerY: y,
});

if (!this._dn.isConnected) {
Expand Down Expand Up @@ -218,6 +235,7 @@ class Scene {
add(...objects) {
objects.flat().map(object => {
this._o.push(object);
object.parent = this;

// move all objects to be in the scenes DOM node so we can
// hide and show the DOM node and thus hide and show all the
Expand All @@ -238,6 +256,7 @@ class Scene {
remove(...objects) {
objects.flat().map(object => {
removeFromArray(this._o, object);
object.parent = null;

getAllNodes(object).map(node => {
addToDom(node, this.context);
Expand Down
2 changes: 2 additions & 0 deletions src/tileEngine.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class TileEngine {
add(...objects) {
objects.flat().map(object => {
this._o.push(object);
object.parent = this;
});
}

Expand All @@ -290,6 +291,7 @@ class TileEngine {
remove(...objects) {
objects.flat().map(object => {
removeFromArray(this._o, object);
object.parent = null;
});
}
// @endif
Expand Down
31 changes: 31 additions & 0 deletions test/integration/scene.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import Sprite from '../../src/sprite.js';
import TileEngine from '../../src/tileEngine.js';
import { init, getCanvas } from '../../src/core.js';
import { depthSort } from '../../src/helpers.js';
import * as pointer from '../../src/pointer.js';
import { noop } from '../../src/utils.js';
import { emit } from '../../src/events.js';

describe('scene integration', () => {
before(() => {
Expand Down Expand Up @@ -64,4 +67,32 @@ describe('scene integration', () => {
expect(spies[2].calledBefore(spies[1])).to.be.true;
expect(spies[1].calledBefore(spies[0])).to.be.true;
});

it('should correctly track objects with pointer when camera is moved', () => {
let pntr = pointer.initPointer({ radius: 1 });
let object = {
x: 100,
y: 50,
width: 10,
height: 20,
render: noop
};
let scene = Scene({
id: 'myId',
objects: [object]
});
pointer.track(object);
object.render();
emit('tick');

pntr.x = 105;
pntr.y = 55;
expect(pointer.pointerOver(object)).to.equal(true);

scene.camera.x += 100;
expect(pointer.pointerOver(object)).to.equal(false);

pntr.x = 5;
expect(pointer.pointerOver(object)).to.equal(true);
});
});
37 changes: 37 additions & 0 deletions test/integration/tileEngine.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
load,
_reset
} from '../../src/assets.js';
import * as pointer from '../../src/pointer.js';
import { noop } from '../../src/utils.js';
import { emit } from '../../src/events.js';
import { init, getCanvas } from '../../src/core.js';

describe('tileEngine integration', () => {
Expand Down Expand Up @@ -145,4 +148,38 @@ describe('tileEngine integration', () => {

expect(func).to.throw();
});

it('should correctly track objects with pointer when camera is moved', done => {
load('/data/tileset/tileset.json', '/data/tileset/bullet.png')
.then(assets => {
let tileEngine = TileEngine(assets[0]);
let pntr = pointer.initPointer({ radius: 1 });
let object = {
x: 100,
y: 50,
width: 10,
height: 20,
render: noop
};

tileEngine.add(object);
pointer.track(object);
object.render();
emit('tick');

tileEngine.mapwidth = 900;

pntr.x = 105;
pntr.y = 55;
expect(pointer.pointerOver(object)).to.equal(true);

tileEngine.sx = 100;
expect(pointer.pointerOver(object)).to.equal(false);

pntr.x = 5;
expect(pointer.pointerOver(object)).to.equal(true);
done();
})
.catch(done);
});
});
30 changes: 30 additions & 0 deletions test/unit/scene.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ describe('scene', () => {
expect(scene.objects.length).to.equal(2);
});

it('should set the objects parent to the scene', () => {
let object = {};
scene.add(object);
expect(object.parent).to.equal(scene);
});

it('should add any objects with DOM nodes to the scenes DOM node', () => {
let object = {
_dn: document.createElement('div')
Expand Down Expand Up @@ -373,6 +379,13 @@ describe('scene', () => {
expect(scene.objects.length).to.equal(0);
});

it('should remove the objects parent', () => {
let object = {};
scene.add(object);
scene.remove(object);
expect(object.parent).to.equal(null);
});

it('should remove any objects with DOM nodes', () => {
let object = {
_dn: document.createElement('div')
Expand Down Expand Up @@ -432,6 +445,15 @@ describe('scene', () => {
expect(scene._dn.contains(node2)).to.be.false;
expect(node1.contains(node2)).to.be.true;
});

it('moving the camera should set the scenes sx and sy properties', () => {
let canvas = scene.context.canvas;
scene.camera.x = 10;
scene.camera.y = 20;

expect(scene.sx).to.equal(10 - canvas.width / 2);
expect(scene.sy).to.equal(20 - canvas.height / 2);
});
});

// --------------------------------------------------
Expand Down Expand Up @@ -542,6 +564,14 @@ describe('scene', () => {
expect(scene.camera.x).to.equal(10);
expect(scene.camera.y).to.equal(10);
});

it('should set the scenes sx and sy properties', () => {
let canvas = scene.context.canvas;
scene.lookAt({ x: 10, y: 20 });

expect(scene.sx).to.equal(10 - canvas.width / 2);
expect(scene.sy).to.equal(20 - canvas.height / 2);
});
});

// --------------------------------------------------
Expand Down
11 changes: 11 additions & 0 deletions test/unit/tileEngine.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,11 @@ describe(
tileEngine.add([obj, {}]);
expect(tileEngine.objects.length).to.equal(2);
});

it('should set the objects parent to the tileEngine', () => {
tileEngine.add(obj);
expect(obj.parent).to.equal(tileEngine);
});
} else {
it('should not exist', () => {
expect(tileEngine.add).to.not.exist;
Expand Down Expand Up @@ -1044,6 +1049,12 @@ describe(
expect(tileEngine.objects.length).to.equal(0);
});

it('should remove the objects parent', () => {
tileEngine.add(obj);
tileEngine.remove(obj);
expect(obj.parent).to.equal(null);
});

it('should not error if the object was not added before', () => {
function fn() {
tileEngine.remove(obj);
Expand Down

0 comments on commit 39f1d19

Please sign in to comment.