Big Forest
Demonstrates the SpriteGPULayer for high-performance rendering of massive sprite counts. It features a procedurally generated environment with parallax layers, weather-based color interpolation, and individual animations for environmental elements like wind-blown leaves, lake sparkles, and rain.
1280 × 720
class Example extends Phaser.Scene
{
activePointer;
scrollSpeed = 0;
scrollSpeedMax = 8;
scrollSpeedAccel = 0.25;
scrollSpeedDecel = 0.5;
gameWidth = 1280;
gameHeight = 720;
preload ()
{
this.load.setBaseURL('https://cdn.phaserfiles.com/v410');
this.load.atlas('big-forest', 'assets/atlas/big-forest.png', 'assets/atlas/big-forest.tp.json');
}
create ()
{
const rnd = new Phaser.Math.RandomDataGenerator('Big Forest');
const gameWidth = this.gameWidth;
const gameHeight = this.gameHeight;
const worldWidth = gameWidth * 1000;
const colorWhite = new Phaser.Display.Color(255, 255, 255);
const colorSky = new Phaser.Display.Color(146, 211, 255);
const colorDark = new Phaser.Display.Color(32, 0, 178);
const GetColor = Phaser.Display.Color.GetColor;
const Interpolate = Phaser.Display.Color.Interpolate.ColorWithColor;
const Blend = (colorA, colorB, n) => {
const color = Interpolate(colorA, colorB, 1, n);
return GetColor(color.r, color.g, color.b);
};
// Create weather bands.
const weather = [];
const weatherCount = 256;
for (let i = 0; i < weatherCount; i++)
{
// A Weather value is a measure of how overcast and rainy it is.
weather.push(rnd.frac());
}
// Blur weather.
for (let i = 0; i < weatherCount - 1; i++)
{
weather[i] = (weather[i] + weather[i + 1]) / 2;
}
// weather[0] = 1;
// weather[1] = 0;
// weather[2] = 1;
// weather[3] = 0;
// Helper function to get the weather at a given normalized position.
const weatherAt = (n) => {
// Interpolate between weather bands.
n = Math.max(Math.min(n, 1), 0);
const i = n * weatherCount;
const i0 = Math.floor(i);
const i1 = Math.ceil(i);
const f = i - i0;
return weather[i0] * (1 - f) + weather[i1] * f;
};
// const weatherAt = (n) => weather[Math.floor(n * weatherCount)];
const layer = this.add.spriteGPULayer('big-forest', 1024 * 1024 * 1.5);
// Create sky.
layer.addMember({
frame: 'Sky',
x: gameWidth / 2,
y: gameHeight / 2,
scaleX: gameWidth / 200,
scaleY: gameHeight / 150,
scrollFactorX: 0,
scrollFactorY: 0
});
// Create mountain row 1.
{
const depth = 100;
const depthVariance = depth / 2;
const size = 1;
const sizeVariance = size * 0.2;
const spacing = 200;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
const frames = ['Mountain1', 'Mountain2'];
let x = 0;
while (x < width)
{
const depthActual = depth + rnd.between(-depthVariance, depthVariance);
const sizeActual = size + rnd.realInRange(-sizeVariance, sizeVariance);
const spacingActual = spacing + rnd.between(-spacingVariance, spacingVariance);
const flip = rnd.sign();
const tint = Blend(colorWhite, colorDark, weatherAt(x / width));
layer.addMember({
frame: rnd.pick(frames),
x: x,
y: gameHeight * 2 / 3 + rnd.between(0, 40),
scaleX: sizeActual * flip,
scaleY: sizeActual,
originY: 1,
scrollFactorX: 1 / depthActual,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
x += spacingActual;
}
}
// Create mountain row 2.
{
const depth = 50;
const depthVariance = depth / 2;
const size = 2;
const sizeVariance = size * 0.2;
const spacing = 400;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
const frames = ['Mountain1', 'Mountain2'];
let x = 0;
while (x < width)
{
const depthActual = depth + rnd.between(-depthVariance, depthVariance);
const sizeActual = size + rnd.realInRange(-sizeVariance, sizeVariance);
const spacingActual = spacing + rnd.between(-spacingVariance, spacingVariance);
const flip = rnd.sign();
const tint = Blend(colorWhite, colorDark, weatherAt(x / width));
layer.addMember({
frame: rnd.pick(frames),
x: x,
y: gameHeight * 2 / 3 + rnd.between(0, 40),
scaleX: sizeActual * flip,
scaleY: sizeActual,
originY: 1,
scrollFactorX: 1 / depthActual,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
x += spacingActual;
}
}
// Add atmospheric perspective 1.
{
const width = worldWidth / weatherCount;
const template = {
frame: 'White2x2',
scaleX: width / 2,
scaleY: gameHeight / 6,
originY: 1,
scrollFactorX: 1 / 50
};
for (let i = 0; i < weatherCount; i++)
{
const weatherL = weatherAt(i / weatherCount);
const weatherR = weatherAt(((i + 1) % weatherCount) / weatherCount);
const colorL = Blend(colorSky, colorDark, weatherL);
const colorR = Blend(colorSky, colorDark, weatherR);
// Solid haze
template.x = i * width;
template.y = gameHeight;
template.tintTopLeft = colorL;
template.tintTopRight = colorR;
template.tintBottomLeft = colorL;
template.tintBottomRight = colorR;
template.alphaTopLeft = 1;
template.alphaTopRight = 1;
layer.addMember(template);
// Gradient haze
template.y = gameHeight * 2 / 3;
template.alphaTopLeft = 0;
template.alphaTopRight = 0;
layer.addMember(template);
}
}
// Add clouds.
const addClouds = (y, scale, depth, alphaMax) => {
const frames = ['Cloud1', 'Cloud2', 'Cloud3'];
const spacing = 10;
const depthVariance = depth / 4;
const width = worldWidth / depth;
const duration = 40000;
const durationVariance = duration / 4;
const spinTime = 160000;
const spinTimeVariance = spinTime / 2;
const template = {
x: {
ease: 'Linear',
amplitude: 200,
yoyo: false
},
rotation: {
base: 0,
ease: 'Linear',
yoyo: false
},
alpha: {
base: 0,
amplitude: 1,
ease: 'Quart'
}
};
for (let i = 0; i < width; i += spacing)
{
const weatherHere = weatherAt(i / width);
if (weatherHere <= rnd.realInRange(0.2, 0.8))
{
continue;
}
const depthActual = depth + rnd.between(-depthVariance, depthVariance);
const durationActual = duration + rnd.between(-durationVariance, durationVariance);
const delay = rnd.between(0, durationActual);
const scaleActual = scale + rnd.realInRange(-scale / 2, scale / 2);
const tint = Blend(colorWhite, colorSky, weatherHere);
template.frame = rnd.pick(frames);
template.x.base = i - 200;
template.x.duration = durationActual;
template.x.delay = delay;
template.y = y + rnd.between(-20, 20);
template.scaleX = scaleActual * rnd.sign();
template.scaleY = scaleActual;
template.scrollFactorX = 1 / depthActual;
template.rotation.amplitude = Math.PI * 2 * rnd.sign();
template.rotation.duration = spinTime + rnd.between(-spinTimeVariance, spinTimeVariance);
template.rotation.delay = rnd.between(0, template.rotation.duration);
template.alpha.amplitude = weatherHere * alphaMax;
template.alpha.duration = durationActual / 8;
template.alpha.delay = delay;
template.tintTopLeft = tint;
template.tintTopRight = tint;
template.tintBottomLeft = tint;
template.tintBottomRight = tint;
layer.addMember(template);
}
};
addClouds(gameHeight / 2, 3, 40, 0.25);
addClouds(gameHeight / 3, 4, 20, 0.75);
addClouds(gameHeight / 4, 5, 10, 1);
addClouds(0, 6, 5, 1);
// Add atmospheric perspective 2.
{
const width = worldWidth / weatherCount;
const template = {
frame: 'White2x2',
y: 0,
scaleX: width / 2,
scaleY: gameHeight / 3,
scrollFactorX: 1 / 50,
originY: 0,
tintTopLeft: colorDark.color,
tintTopRight: colorDark.color,
tintBottomLeft: colorDark.color,
tintBottomRight: colorDark.color,
alphaBottomLeft: 0,
alphaBottomRight: 0
};
for (let i = 0; i < weatherCount; i++)
{
// Gradient haze
template.x = i * width;
template.alphaTopLeft = weatherAt(i / weatherCount) * 0.5 + 0.5;
template.alphaTopRight = weatherAt(((i + 1) % weatherCount) / weatherCount) * 0.5 + 0.5;
layer.addMember(template);
}
}
// Add lake sparkles.
{
const template = {
frame: 'White2x2',
scrollFactorX: 0,
alpha: {
base: 0,
ease: 'Smoothstep.easeInOut',
duration: 2000
}
};
const halfWidth = gameWidth / 2;
for (let y = gameHeight * 2 / 3; y < gameHeight; y++)
{
const h = (y - gameHeight * 2 / 3) / (gameHeight / 3);
template.alpha.amplitude = h;
template.alpha.delay = y * 128;
template.y = y;
template.scaleX = rnd.between(64, 128);
let deviation = Math.pow(rnd.frac(), 1 / 4) * rnd.sign();
if (y % 2 === 0)
{
template.alpha.amplitude *= 0.25;
template.tintTopLeft = colorDark.color;
template.tintTopRight = colorDark.color;
template.tintBottomLeft = colorDark.color;
template.tintBottomRight = colorDark.color;
}
else
{
deviation = Math.pow(rnd.frac(), 4) * rnd.sign();
template.tintTopLeft = colorWhite.color;
template.tintTopRight = colorWhite.color;
template.tintBottomLeft = colorWhite.color;
template.tintBottomRight = colorWhite.color;
}
template.x = deviation * halfWidth + halfWidth;
layer.addMember(template);
}
}
const groundStrips = 8;
const getGroundStripHeight = (x, strip) => {
// x is the world coordinate.
// strip is the strip of ground elements, dictating ground wave function.
// Returns a height between 0 and 1.
const phase = x + strip * 1000;
return (Math.cos(phase / 64) * Math.sin(phase / 37)) * 0.5 + 0.5;
};
// Add trees.
const addTree = (x, y, scale, depth, darkness, skipTrunk) => {
// Trees are assembled from a stump, a number of trunk segments,
// and a number of leaf layers.
// X is in world coordinates, and will be modified by depth.
if (skipTrunk === undefined)
{
skipTrunk = false;
}
const stumpFrames = ['Stump1', 'Stump2'];
const trunkFrames = ['Trunk1', 'Trunk2', 'Trunk3', 'Trunk4'];
const leafFrames = ['Leaves1', 'Leaves2'];
const looseLeafFrames = ['LooseLeaves1', 'LooseLeaves2', 'LooseLeaves3'];
const trunkCount = rnd.between(1, 4);
const leafCount = rnd.between(2, 8);
const stumpLength = 0;
const trunkLength = 48 * scale;
const leafLength = 12 * scale;
const leafScatter = 32 * scale;
let x1 = x;
let y1 = y;
let angle = 0;
const tint = Blend(colorWhite, colorDark, darkness);
let vec2 = new Phaser.Math.Vector2();
if (!skipTrunk)
{
// Add stump.
layer.addMember({
frame: rnd.pick(stumpFrames),
x: x1,
y: y1,
scaleX: scale * rnd.sign(),
scaleY: scale,
scrollFactorX: 1 / depth,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
vec2 = new Phaser.Math.Vector2(0, -stumpLength);
vec2.rotate(angle);
x1 += vec2.x;
y1 += vec2.y;
angle += rnd.realInRange(-0.2, 0.2);
// Add trunk segments.
for (let i = 0; i < trunkCount; i++)
{
layer.addMember({
frame: rnd.pick(trunkFrames),
x: x1,
y: y1,
rotation: angle,
scaleX: scale * rnd.sign(),
scaleY: scale,
scrollFactorX: 1 / depth,
originY: 1,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
vec2.setTo(0, -trunkLength);
vec2.rotate(angle);
x1 += vec2.x;
y1 += vec2.y;
angle += rnd.realInRange(-0.2, 0.2);
}
}
// Add leaf layers.
const rotationTemplate = {
ease: 'Smoothstep.easeInOut'
};
const xTemplate = {
ease: 'Smoothstep.easeInOut'
}
let windSpeed = 1 + rnd.frac();
for (let i = 0; i < leafCount; i++)
{
const duration = 5000 + rnd.between(-1500, 1500);
const delay = rnd.between(0, duration);
const offset = new Phaser.Math.Vector2(rnd.between(-leafLength, leafLength), 0);
offset.rotate(angle);
const leafScale = (0.5 + rnd.realInRange(0, 0.5)) * scale;
xTemplate.base = x1 + offset.x;
xTemplate.amplitude = windSpeed * 2;
xTemplate.duration = duration;
xTemplate.delay = delay;
rotationTemplate.base = angle - rnd.realInRange(-0.2, 0.2);
rotationTemplate.amplitude = windSpeed * 0.05;
rotationTemplate.duration = duration;
rotationTemplate.delay = xTemplate.delay - xTemplate.duration / 4;
layer.addMember({
frame: rnd.pick(leafFrames),
x: xTemplate,
y: y1 + offset.y,
rotation: rotationTemplate,
scaleX: leafScale * rnd.sign(),
scaleY: leafScale,
scrollFactorX: 1 / depth,
originY: 1,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
// Advance to higher section.
vec2.setTo(0, -leafLength);
vec2.rotate(angle);
x1 += vec2.x;
y1 += vec2.y;
angle += rnd.realInRange(-0.2, 0.2);
windSpeed += rnd.frac();
// Add loose leaves.
const looseLeafCount = rnd.between(1, 3);
for (let j = 0; j < looseLeafCount; j++)
{
const offset2 = new Phaser.Math.Vector2(leafScatter, 0);
offset2.rotate(rnd.rotation());
const leafScale = (0.5 + rnd.realInRange(0, 0.5)) * scale;
xTemplate.base = x1 + offset.x + offset2.x;
xTemplate.amplitude = windSpeed * 2;
xTemplate.delay = delay + duration / 4;
rotationTemplate.base = angle - rnd.realInRange(-0.2, 0.2);
rotationTemplate.delay = xTemplate.delay;
layer.addMember({
frame: rnd.pick(looseLeafFrames),
x: xTemplate,
y: y1 + offset.y + offset2.y,
rotation: rotationTemplate,
scaleX: leafScale * rnd.sign(),
scaleY: leafScale,
scrollFactorX: 1 / depth,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
}
}
};
// Create background canopy.
{
const depth = 2;
const spacing = 100;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
for (let x = 0; x < width; x += spacing)
{
const xActual = x + rnd.between(-spacingVariance, spacingVariance);
const darkness = 0.5 + 0.5 * weatherAt(xActual / width);
const worldX = xActual / depth;
let groundHeight = 0;
for (let strip = 0; strip <= groundStrips; strip++)
{
groundHeight += getGroundStripHeight(worldX, strip);
}
addTree(
xActual,
gameHeight - 12 * groundHeight,
1,
depth,
darkness,
true
);
}
}
// Create tree row 1.
{
const depth = 1.8;
const spacing = 150;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
for (let x = 0; x < width; x += spacing)
{
const xActual = x + rnd.between(-spacingVariance, spacingVariance);
const darkness = 0.5 + 0.5 * weatherAt(xActual / width);
const worldX = xActual / depth;
let groundHeight = 0;
for (let strip = 0; strip <= groundStrips; strip++)
{
groundHeight += getGroundStripHeight(worldX, strip);
}
addTree(
xActual,
gameHeight - 24 * groundHeight,
1,
depth,
darkness
);
}
}
// Create tree row 2.
{
const depth = 1.6;
const spacing = 250;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
for (let x = 0; x < width; x += spacing)
{
const xActual = x + rnd.between(-spacingVariance, spacingVariance);
const darkness = 0.25 + 0.75 * weatherAt(xActual / width);
const worldX = xActual / depth;
let groundHeight = 0;
for (let strip = 0; strip <= groundStrips; strip++)
{
groundHeight += getGroundStripHeight(worldX, strip);
}
addTree(
xActual,
gameHeight - 24 * groundHeight,
1.5 - rnd.realInRange(0, 0.5),
depth,
darkness
);
}
}
// Create tree row 3.
{
const depth = 1.4;
const spacing = 400;
const spacingVariance = spacing / 2;
const width = worldWidth / depth;
for (let x = 0; x < width; x += spacing)
{
const xActual = x + rnd.between(-spacingVariance, spacingVariance);
const darkness = weatherAt(xActual / width);
const worldX = xActual / depth;
let groundHeight = 0;
for (let strip = 0; strip <= groundStrips; strip++)
{
groundHeight += getGroundStripHeight(worldX, strip);
}
addTree(
xActual,
gameHeight - 24 * groundHeight,
2 - rnd.realInRange(0, 0.5),
depth,
darkness
);
}
}
// Add ground.
const addGround = (strip) => {
const depth = strip * 0.04;
const scaleFactor = 1 / (1 + depth);
const groundSize = 24;
const spacing = groundSize * scaleFactor;
const frames = ['Ground1', 'Ground2', 'Ground3', 'Ground4'];
const grassFrames = ['Grass1', 'Grass2', 'Grass3', 'Grass4', 'Grass5'];
const detailFrames = ['Detail1', 'Detail2', 'Detail3', 'Detail4'];
let lastHeight = 0;
for (let s = 0; s <= strip; s++)
{
lastHeight += getGroundStripHeight(0, s);
}
const rotationTemplate = {
ease: 'Smoothstep.easeInOut',
amplitude: 0.2
};
const width = worldWidth * scaleFactor;
for (let i = 0; i < width; i += spacing)
{
let height = 0;
for (let s = 0; s <= strip; s++)
{
height += getGroundStripHeight(i, s);
}
const heightDelta = lastHeight - height;
const angle = Math.atan2(heightDelta, 1);
const cosine = Math.cos(angle);
const sine = Math.sin(angle);
const weatherHere = weatherAt(i / width);
const tint = Blend(colorWhite, colorDark, weatherHere);
const y = gameHeight - groundSize * (height - 1);
// Add grass.
rotationTemplate.base = angle - rnd.realInRange(-0.1, 0.1);
rotationTemplate.duration = 1000 + rnd.between(-500, 500);
rotationTemplate.delay = rnd.between(0, rotationTemplate.duration);
let rise = rnd.between(0, 8);
let slide = rnd.between(-4, 4);
layer.addMember({
frame: rnd.pick(grassFrames),
x: i + cosine * rise + sine * rise,
y: y + sine * slide - cosine * slide,
rotation: rotationTemplate,
scaleX: 2 * scaleFactor * rnd.sign(),
scaleY: 2 * scaleFactor,
originY: 1,
scrollFactorX: scaleFactor,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
// Add ground.
layer.addMember({
frame: rnd.pick(frames),
x: i,
y: y,
rotation: angle,
scaleX: 2 * scaleFactor * rnd.sign(),
scaleY: 2 * scaleFactor,
scrollFactorX: scaleFactor,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
// Add detail.
if (rnd.frac() < 0.1)
{
rise = rnd.between(-4, 4);
slide = rnd.between(-4, 4);
layer.addMember({
frame: rnd.pick(detailFrames),
x: i + cosine * rise + sine * rise,
y: y + sine * slide - cosine * slide,
rotation: angle + rnd.realInRange(-0.3, 0.3),
scaleX: 2 * scaleFactor * rnd.sign(),
scaleY: 2 * scaleFactor,
scrollFactorX: scaleFactor,
tintTopLeft: tint,
tintTopRight: tint,
tintBottomLeft: tint,
tintBottomRight: tint
});
}
lastHeight = height;
}
};
for (let strip = groundStrips; strip >= 0; strip--)
{
addGround(strip);
}
// Add rain and pollen.
{
const length = 256;
const yRepeats = 4;
const templateRain = {
frame: 'White2x2',
x: {
ease: 'Linear',
yoyo: false
},
y: {
ease: 'Linear',
yoyo: false
},
alphaTopLeft: 0,
alphaBottomLeft: 0,
alpha: 0.1
};
const templatePollen = {
frame: 'White2x2',
x: {
ease: 'Linear',
yoyo: false
},
y: {
ease: 'Linear',
yoyo: false
},
rotation: {
ease: 'Linear',
yoyo: false
},
tintTopLeft: 0xffffaa,
tintTopRight: 0xffffaa,
tintBottomLeft: 0xffffaa,
tintBottomRight: 0xffffaa,
alpha: {
base: 0,
ease: 'Smoothstep.easeInOut'
}
};
for (let i = 0; i < worldWidth; i += 2)
{
const chanceOfRaindrop = weatherAt(i / worldWidth) - 0.5;
const chanceOfPollen = (1 - weatherAt(i / worldWidth)) - 0.5;
if (rnd.frac() < chanceOfRaindrop)
{
const closeness = 0.5 + rnd.frac();
const duration = 1000 - 500 * closeness;
const delay = rnd.between(0, duration);
const angle = Math.PI * 11 / 24 + rnd.realInRange(-0.1, 0.1);
const y = gameHeight + 256;
const x = y / Math.sin(angle);
templateRain.x.base = i - 300;
templateRain.x.amplitude = x * Math.cos(angle) * yRepeats;
templateRain.x.duration = duration * yRepeats;
templateRain.x.delay = delay;
templateRain.y.base = -128;
templateRain.y.amplitude = y;
templateRain.y.duration = duration;
templateRain.y.delay = delay;
templateRain.rotation = angle;
templateRain.scaleX = length * closeness;
templateRain.scaleY = closeness;
layer.addMember(templateRain);
}
else if (rnd.frac() < chanceOfPollen)
{
const duration = rnd.between(10000, 20000);
const delay = rnd.between(0, duration);
templatePollen.x.base = i - 300;
templatePollen.x.amplitude = rnd.between(200, 600);
templatePollen.x.duration = duration;
templatePollen.x.delay = delay;
templatePollen.y.base = gameHeight - Math.pow(rnd.frac(), 2) * 300;
templatePollen.y.amplitude = -rnd.between(50, 150);
templatePollen.y.duration = duration;
templatePollen.y.delay = delay;
templatePollen.originX = rnd.between(1, 8);
templatePollen.rotation.base = rnd.realInRange(0, Math.PI * 2);
templatePollen.rotation.amplitude = Math.PI * 2 * rnd.sign();
templatePollen.rotation.duration = rnd.between(4000, 10000);
templatePollen.scaleX = rnd.realInRange(1, 2);
templatePollen.scaleY = templatePollen.scaleX;
templatePollen.alpha.amplitude = rnd.realInRange(0.1, 0.5);
templatePollen.alpha.duration = duration / 2;
templatePollen.alpha.delay = delay;
layer.addMember(templatePollen);
}
}
}
//
// Add input handling.
//
this.add.text(gameWidth / 2, 16, layer.memberCount + ' sprites in 1 object. Press left and right sides to scroll').setOrigin(0.5, 0);
this.input.on('pointerdown', (pointer) => {
this.activePointer = pointer;
});
this.input.on('pointerup', (pointer) => {
if (this.activePointer === pointer)
{
this.activePointer = null;
}
});
this.input.on('pointerupoutside', (pointer) => {
if (this.activePointer === pointer)
{
this.activePointer = null;
}
});
}
update (time, delta)
{
const cam = this.cameras.main;
// cam.setScroll(cam.scrollX + delta / 32, 0);
let scrollInput = false;
if (this.activePointer)
{
const pointer = this.activePointer;
if (pointer.x < this.gameWidth / 3)
{
this.scrollSpeed = Math.max(this.scrollSpeed - this.scrollSpeedAccel, -this.scrollSpeedMax);
scrollInput = true;
}
else if (pointer.x > this.gameWidth * 2 / 3)
{
this.scrollSpeed = Math.min(this.scrollSpeed + this.scrollSpeedAccel, this.scrollSpeedMax);
scrollInput = true;
}
}
if (!scrollInput)
{
// Slow down.
this.scrollSpeed = Math.max(Math.abs(this.scrollSpeed) - this.scrollSpeedDecel, 0) * Math.sign(this.scrollSpeed);
}
cam.setScroll(cam.scrollX + this.scrollSpeed, 0);
// Prevent camera from scrolling off the edge.
if (cam.scrollX < 0)
{
cam.setScroll(0, 0);
this.scrollSpeed = 0;
}
}
}
const config = {
scale: { mode: Phaser.Scale.FIT },
type: Phaser.WEBGL,
parent: 'game-container',
width: 1280,
height: 720,
scene: Example,
backgroundColor: '#808080',
// pixelArt: true
smoothPixelArt: true
};
const game = new Phaser.Game(config);
console.log(game);