Skip to content

Commit f8cda69

Browse files
committed
Added Camera.lerp and implemented linear interpolation when following targets
1 parent 57c2ccb commit f8cda69

2 files changed

Lines changed: 58 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
* Arcade Physics Body has a new method `setAllowGravity` which toggles the `allowGravity` property (thanks @samme)
1212
* Arcade Physics Body has a new method `setAllowRotation` which toggles the `allowRotation` property (thanks @samme)
1313
* Arcade Physics Group Config has 3 new properties you can use: `allowDrag`, `allowGravity` and `allowRotation` (thanks @samme)
14+
* PluginManager.registerFileType has a new property `addToScene` which allows you to inject the new file type into the LoaderPlugin of the given Scene. You could use this to add the file type into the Scene in which it was loaded.
15+
* PluginManager.install has a new property `mapping`. This allows you to give a Global Plugin a property key, so that it is automatically injected into any Scenes as a Scene level instance. This allows you to have a single global plugin running in the PluginManager, that is injected into every Scene automatically.
16+
* Camera.lerp has been implemented and allows you to specify the linear interpolation value used when following a target, to provide for smoothed camera tracking.
17+
* Camera.startFollow has 2 new arguments: `lerpX` and `lerpY` which allow you to set the interpolation value used when following the target. The default is 1 (no interpolation).
18+
* Camera.startFollow will now immediately set the camera scrollX and Y values to be that of the target to avoid large initial lerps during the first few preUpdates.
1419

1520
### Updates
1621

1722
* Container.setInteractive can now be called without any arguments as long as you have called Container.setSize first (thanks rex)
1823
* Bob.reset will now reset the position, frame, flip, visible and alpha values of the Bob.
1924
* VisibilityHandler now takes a game instance as its sole argument, instead of an event emitter.
20-
* PluginManager.registerFileType has a new property `addToScene` which allows you to inject the new file type into the LoaderPlugin of the given Scene. You could use this to add the file type into the Scene in which it was loaded.
21-
* PluginManager.install has a new property `mapping`. This allows you to give a Global Plugin a property key, so that it is automatically injected into any Scenes as a Scene level instance. This allows you to have a single global plugin running in the PluginManager, that is injected into every Scene automatically.
2225
* PluginManager.createEntry is a new private method to create a plugin entry and return it. This avoids code duplication in several other methods, which now use this instead.
2326
* The Plugin File Type has a new optional argument `mapping`, which allows a global plugin to be injected into a Scene as a reference.
2427
* TileSprite.destroy has been renamed to `preDestroy` to take advantage of the preDestroy callback system.
@@ -37,14 +40,12 @@
3740
* Fix TypeError when colliding a Group as the only argument in Arcade Physics. Fix #3665 (thanks @samme)
3841
* The Particle tint value was incorrectly calculated, causing the color channels to be inversed. Fix #3643 (thanks @rgk)
3942
* All Game Objects that were in Containers were being destroyed twice when a Scene was shutdown. Although not required it still worked in most cases, except with TileSprites. TileSprites specifically have been hardened against this now but all Game Objects inside Containers now have a different event flow, stopping them from being destroyed twice (thanks @laptou @PaNaVTEC)
40-
* Camera.cull will now accurately return only the Game Objects in the camera's view, instead of them all. Fix #3646 (thanks @KingCosmic @Yora)
43+
* Camera.cull will now accurately return only the Game Objects in the camera view, instead of them all. Fix #3646 (thanks @KingCosmic @Yora)
4144
* The `dragend` event would be broadcast even if the drag distance or drag time thresholds were not met. Fix #3686 (thanks @RollinSafary)
4245
* Restarting a Tween immediately after creating it, without it having first started, would cause it to get stuck permanently in the Tween Managers add queue (thanks @Antriel @zacharysarette)
4346
* Setting an existing Game Object as a static Arcade Physics body would sometimes incorrectly pick-up the dimensions of the object, such as with TileSprites. Fix #3690 (thanks @fariazz)
4447
* Interactive Objects were not fully removed from the Input Plugin when cleared, causing the internal _list array to grow. Fix #3645 (thanks @tjb295 for the fix and @rexrainbow for the issue)
4548

46-
Changes the checks for Camera.cull to give only the game objects in the camera's view instead of all game objects
47-
4849
### Examples, Documentation and TypeScript
4950

5051
My thanks to the following for helping with the Phaser 3 Examples, Docs and TypeScript definitions, either by reporting errors, fixing them or helping author the docs:

src/cameras/2d/Camera.js

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
55
*/
66

7+
var Clamp = require('../../math/Clamp');
78
var Class = require('../../utils/Class');
89
var DegToRad = require('../../math/DegToRad');
9-
var EventEmitter = require('eventemitter3');
1010
var Effects = require('./effects');
11+
var EventEmitter = require('eventemitter3');
12+
var Linear = require('../../math/Linear');
1113
var Rectangle = require('../../geom/rectangle/Rectangle');
1214
var TransformMatrix = require('../../gameobjects/components/TransformMatrix');
1315
var ValueToColor = require('../../display/color/ValueToColor');
@@ -300,6 +302,22 @@ var Camera = new Class({
300302
*/
301303
this.culledObjects = [];
302304

305+
/**
306+
* The linear interpolation value to use when following a target.
307+
*
308+
* The default values of 1 means the camera will instantly snap to the target coordinates.
309+
* A lower value, such as 0.1 means the camera will more slowly track the target, giving
310+
* a smooth transition. You can set the horizontal and vertical values independently, and also
311+
* adjust this value in real-time during your game.
312+
*
313+
* Be sure to keep the value between 0 and 1. A value of zero will disable tracking on that axis.
314+
*
315+
* @name Phaser.Cameras.Scene2D.Camera#lerp
316+
* @type {Phaser.Math.Vector2}
317+
* @since 3.9.0
318+
*/
319+
this.lerp = new Vector2(1, 1);
320+
303321
/**
304322
* Internal follow target reference.
305323
*
@@ -683,13 +701,10 @@ var Camera = new Class({
683701
var originY = height / 2;
684702
var follow = this._follow;
685703

686-
if (follow !== null)
704+
if (follow)
687705
{
688-
originX = follow.x;
689-
originY = follow.y;
690-
691-
this.scrollX = (originX - width * 0.5) / zoom;
692-
this.scrollY = (originY - height * 0.5) / zoom;
706+
this.scrollX = Linear(this.scrollX, follow.x - originX, this.lerp.x) / zoom;
707+
this.scrollY = Linear(this.scrollY, follow.y - originY, this.lerp.y) / zoom;
693708
}
694709

695710
if (this.useBounds)
@@ -1034,22 +1049,47 @@ var Camera = new Class({
10341049
*
10351050
* When enabled the Camera will automatically adjust its scroll position to keep the target Game Object
10361051
* in its center.
1052+
*
1053+
* You can set the linear interpolation value used in the follow code.
1054+
* Use low lerp values (such as 0.1) to automatically smooth the camera motion.
1055+
*
1056+
* If you find you're getting a slight "jitter" effect when following an object it's probably to do with sub-pixel
1057+
* rendering of the targets position. This can be rounded by setting the `roundPixels` argument to `true` to
1058+
* force full pixel rounding rendering. Note that this can still be broken if you have specified a non-integer zoom
1059+
* value on the camera. So be sure to keep the camera zoom to integers.
10371060
*
10381061
* @method Phaser.Cameras.Scene2D.Camera#startFollow
10391062
* @since 3.0.0
10401063
*
10411064
* @param {(Phaser.GameObjects.GameObject|object)} target - The target for the Camera to follow.
1042-
* @param {boolean} [roundPx=false] - Round the movement pixels to whole integers?
1065+
* @param {boolean} [roundPixels=false] - Round the camera position to whole integers to avoid sub-pixel rendering?
1066+
* @param {float} [lerpX=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when horizontally tracking the target. The closer the value to 1, the faster the camera will track.
1067+
* @param {float} [lerpY=1] - A value between 0 and 1. This value specifies the amount of linear interpolation to use when vertically tracking the target. The closer the value to 1, the faster the camera will track.
10431068
*
1044-
* @return {Phaser.Cameras.Scene2D.Camera} This Camera instance.
1069+
* @return {this} This Camera instance.
10451070
*/
1046-
startFollow: function (target, roundPx)
1071+
startFollow: function (target, roundPixels, lerpX, lerpY)
10471072
{
1048-
if (roundPx === undefined) { roundPx = false; }
1073+
if (roundPixels === undefined) { roundPixels = false; }
1074+
if (lerpX === undefined) { lerpX = 1; }
1075+
if (lerpY === undefined) { lerpY = lerpX; }
10491076

10501077
this._follow = target;
10511078

1052-
this.roundPixels = roundPx;
1079+
this.roundPixels = roundPixels;
1080+
1081+
lerpX = Clamp(lerpX, 0, 1);
1082+
lerpY = Clamp(lerpY, 0, 1);
1083+
1084+
this.lerp.set(lerpX, lerpY);
1085+
1086+
// Move the camera there immediately, to avoid a large lerp during preUpdate
1087+
var zoom = this.zoom;
1088+
var originX = this.width / 2;
1089+
var originY = this.height / 2;
1090+
1091+
this.scrollX = (target.x - originX) / zoom;
1092+
this.scrollY = (target.y - originY) / zoom;
10531093

10541094
return this;
10551095
},

0 commit comments

Comments
 (0)