feat: sync illustrated forest asset integration
This commit is contained in:
parent
3d35489209
commit
c3a5aecdbd
260
src/main.js
260
src/main.js
@ -15,12 +15,44 @@ class ForestScene extends Phaser.Scene {
|
|||||||
this.touchPointers = { left: new Set(), right: new Set() };
|
this.touchPointers = { left: new Set(), right: new Set() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.cameras.main.setBackgroundColor('#10251d');
|
||||||
|
|
||||||
|
const cx = this.scale.width / 2;
|
||||||
|
const cy = this.scale.height / 2;
|
||||||
|
const label = this.add.text(cx, cy - 28, 'Growing the forest…', {
|
||||||
|
fontFamily: 'Georgia, serif',
|
||||||
|
fontSize: '20px',
|
||||||
|
color: '#e7ead9'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
const track = this.add.rectangle(cx, cy + 12, 220, 8, 0x294235).setOrigin(0.5);
|
||||||
|
const fill = this.add.rectangle(cx - 110, cy + 12, 0, 8, 0xb6c97a).setOrigin(0, 0.5);
|
||||||
|
|
||||||
|
this.load.on('progress', value => {
|
||||||
|
fill.width = 220 * value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.load.on('complete', () => {
|
||||||
|
label.destroy();
|
||||||
|
track.destroy();
|
||||||
|
fill.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.load.image('player-sheet', '/assets/player-sheet.png');
|
||||||
|
this.load.image('flora-sheet', '/assets/flora-sheet.png');
|
||||||
|
this.load.image('fauna-sheet', '/assets/fauna-sheet.png');
|
||||||
|
this.load.image('terrain-sheet', '/assets/terrain-sheet.png');
|
||||||
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
this.physics.world.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);
|
this.physics.world.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);
|
||||||
this.cameras.main.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);
|
this.cameras.main.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);
|
||||||
this.cameras.main.setBackgroundColor('#8fc7a2');
|
this.cameras.main.setBackgroundColor('#8fc7a2');
|
||||||
|
|
||||||
this.createTextures();
|
this.createTextures();
|
||||||
|
this.createArtFrames();
|
||||||
|
this.createAnimations();
|
||||||
this.createBackdrop();
|
this.createBackdrop();
|
||||||
this.createWorld();
|
this.createWorld();
|
||||||
this.createPlayer();
|
this.createPlayer();
|
||||||
@ -70,6 +102,105 @@ class ForestScene extends Phaser.Scene {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createArtFrames() {
|
||||||
|
const addFrame = (textureKey, name, x, y, width, height) => {
|
||||||
|
this.textures.get(textureKey).add(name, 0, x, y, width, height);
|
||||||
|
};
|
||||||
|
|
||||||
|
[
|
||||||
|
['idle0', 0, 70, 145, 185],
|
||||||
|
['idle1', 130, 70, 150, 185],
|
||||||
|
['idle2', 260, 70, 150, 185],
|
||||||
|
['idle3', 385, 70, 170, 185],
|
||||||
|
['run0', 575, 75, 165, 180],
|
||||||
|
['run1', 715, 75, 165, 180],
|
||||||
|
['run2', 855, 75, 165, 180],
|
||||||
|
['run3', 995, 75, 165, 180],
|
||||||
|
['run4', 1130, 75, 175, 180],
|
||||||
|
['run5', 1270, 75, 178, 180],
|
||||||
|
['jump0', 0, 315, 190, 195],
|
||||||
|
['jump1', 175, 315, 200, 195],
|
||||||
|
['fall0', 470, 315, 170, 195],
|
||||||
|
['fall1', 625, 315, 175, 195],
|
||||||
|
['land0', 955, 325, 225, 185],
|
||||||
|
['land1', 1185, 325, 205, 185]
|
||||||
|
].forEach(([name, x, y, w, h]) => addFrame('player-sheet', name, x, y, w, h));
|
||||||
|
|
||||||
|
addFrame('terrain-sheet', 'ground-main', 10, 18, 500, 132);
|
||||||
|
addFrame('terrain-sheet', 'log-platform', 10, 315, 290, 105);
|
||||||
|
addFrame('terrain-sheet', 'root-platform', 995, 650, 430, 205);
|
||||||
|
|
||||||
|
addFrame('flora-sheet', 'bush', 5, 18, 260, 165);
|
||||||
|
addFrame('flora-sheet', 'fern-cluster', 450, 0, 390, 180);
|
||||||
|
addFrame('flora-sheet', 'bluebells', 0, 170, 365, 150);
|
||||||
|
addFrame('flora-sheet', 'mush-red', 0, 310, 185, 220);
|
||||||
|
addFrame('flora-sheet', 'mush-brown', 370, 310, 215, 220);
|
||||||
|
addFrame('flora-sheet', 'mush-orange', 545, 315, 145, 215);
|
||||||
|
addFrame('flora-sheet', 'mush-purple', 670, 310, 210, 220);
|
||||||
|
addFrame('flora-sheet', 'mush-blue', 930, 310, 310, 220);
|
||||||
|
addFrame('flora-sheet', 'acorn-art', 10, 525, 90, 120);
|
||||||
|
|
||||||
|
const frogFrames = [
|
||||||
|
[40, 500, 165, 150], [200, 500, 190, 150], [390, 500, 190, 150],
|
||||||
|
[570, 500, 220, 150], [810, 500, 175, 150]
|
||||||
|
];
|
||||||
|
frogFrames.forEach(([x, y, w, h], i) => addFrame('fauna-sheet', `frog${i}`, x, y, w, h));
|
||||||
|
|
||||||
|
const hedgehogFrames = [
|
||||||
|
[0, 45, 155, 145], [145, 45, 155, 145], [285, 45, 160, 145],
|
||||||
|
[425, 45, 160, 145], [565, 45, 160, 145], [700, 45, 155, 145]
|
||||||
|
];
|
||||||
|
hedgehogFrames.forEach(([x, y, w, h], i) => addFrame('fauna-sheet', `hedgehog${i}`, x, y, w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
createAnimations() {
|
||||||
|
const frames = (texture, names) => names.map(frame => ({ key: texture, frame }));
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'squirrel-idle',
|
||||||
|
frames: frames('player-sheet', ['idle0', 'idle1', 'idle2', 'idle3']),
|
||||||
|
frameRate: 4,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'squirrel-run',
|
||||||
|
frames: frames('player-sheet', ['run0', 'run1', 'run2', 'run3', 'run4', 'run5']),
|
||||||
|
frameRate: 12,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'squirrel-jump',
|
||||||
|
frames: frames('player-sheet', ['jump0', 'jump1']),
|
||||||
|
frameRate: 8,
|
||||||
|
repeat: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'squirrel-fall',
|
||||||
|
frames: frames('player-sheet', ['fall0', 'fall1']),
|
||||||
|
frameRate: 5,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'frog-hop',
|
||||||
|
frames: frames('fauna-sheet', ['frog0', 'frog1', 'frog2', 'frog3', 'frog4']),
|
||||||
|
frameRate: 7,
|
||||||
|
repeat: -1,
|
||||||
|
repeatDelay: 1400
|
||||||
|
});
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'hedgehog-walk',
|
||||||
|
frames: frames('fauna-sheet', ['hedgehog0', 'hedgehog1', 'hedgehog2', 'hedgehog3', 'hedgehog4', 'hedgehog5']),
|
||||||
|
frameRate: 8,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
createTextures() {
|
createTextures() {
|
||||||
const g = this.make.graphics({ add: false });
|
const g = this.make.graphics({ add: false });
|
||||||
|
|
||||||
@ -234,11 +365,16 @@ class ForestScene extends Phaser.Scene {
|
|||||||
createWorld() {
|
createWorld() {
|
||||||
this.platforms = this.physics.add.staticGroup();
|
this.platforms = this.physics.add.staticGroup();
|
||||||
|
|
||||||
const ground = this.add.rectangle(WORLD_WIDTH / 2, GROUND_Y + 46, WORLD_WIDTH, 100, 0x263c2d);
|
const ground = this.add.rectangle(WORLD_WIDTH / 2, GROUND_Y + 46, WORLD_WIDTH, 100, 0x263c2d, 0);
|
||||||
this.physics.add.existing(ground, true);
|
this.physics.add.existing(ground, true);
|
||||||
this.platforms.add(ground);
|
this.platforms.add(ground);
|
||||||
|
|
||||||
this.add.rectangle(WORLD_WIDTH / 2, GROUND_Y + 2, WORLD_WIDTH, 20, 0x55714a);
|
for (let x = 215; x < WORLD_WIDTH + 220; x += 430) {
|
||||||
|
this.add.image(x, GROUND_Y - 5, 'terrain-sheet', 'ground-main')
|
||||||
|
.setOrigin(0.5, 0)
|
||||||
|
.setScale(0.9)
|
||||||
|
.setDepth(3);
|
||||||
|
}
|
||||||
|
|
||||||
const branchPositions = [
|
const branchPositions = [
|
||||||
[500, 545], [720, 505], [900, 465],
|
[500, 545], [720, 505], [900, 465],
|
||||||
@ -250,24 +386,45 @@ class ForestScene extends Phaser.Scene {
|
|||||||
];
|
];
|
||||||
|
|
||||||
branchPositions.forEach(([x, y], index) => {
|
branchPositions.forEach(([x, y], index) => {
|
||||||
const branch = this.platforms.create(x, y, 'branch');
|
const scale = index % 3 === 0 ? 0.62 : 0.55;
|
||||||
branch.setScale(index % 3 === 0 ? 1.35 : 1);
|
const visual = this.add.image(x, y + 15, 'terrain-sheet', 'log-platform')
|
||||||
branch.refreshBody();
|
.setScale(scale)
|
||||||
|
.setDepth(6);
|
||||||
|
|
||||||
|
const collider = this.add.rectangle(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
Math.max(130, visual.displayWidth * 0.82),
|
||||||
|
16,
|
||||||
|
0x000000,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
this.physics.add.existing(collider, true);
|
||||||
|
this.platforms.add(collider);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let x = 90; x < WORLD_WIDTH - 120; x += 105) {
|
for (let x = 120; x < WORLD_WIDTH - 120; x += 180) {
|
||||||
const n = Math.sin(x * 0.013) + Math.cos(x * 0.021);
|
const n = Math.sin(x * 0.013) + Math.cos(x * 0.021);
|
||||||
if (n > -0.15) {
|
if (n > -0.3) {
|
||||||
this.add.image(x, GROUND_Y - 10, 'fern')
|
this.add.image(x, GROUND_Y - 2, 'flora-sheet', 'fern-cluster')
|
||||||
.setOrigin(0.5, 1)
|
.setOrigin(0.5, 1)
|
||||||
.setScale(0.65 + ((x % 70) / 160))
|
.setScale(0.2 + ((x % 90) / 900))
|
||||||
.setAlpha(0.85);
|
.setAlpha(0.96)
|
||||||
|
.setDepth(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x % 315 < 130) {
|
if (x % 540 < 190) {
|
||||||
this.add.image(x + 34, GROUND_Y - 5, 'flower')
|
this.add.image(x + 65, GROUND_Y - 2, 'flora-sheet', 'bluebells')
|
||||||
.setOrigin(0.5, 1)
|
.setOrigin(0.5, 1)
|
||||||
.setScale(0.7 + ((x % 50) / 170));
|
.setScale(0.2)
|
||||||
|
.setDepth(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x % 900 < 190) {
|
||||||
|
this.add.image(x - 65, GROUND_Y - 3, 'flora-sheet', 'bush')
|
||||||
|
.setOrigin(0.5, 1)
|
||||||
|
.setScale(0.34)
|
||||||
|
.setDepth(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,13 +453,14 @@ class ForestScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createPlayer() {
|
createPlayer() {
|
||||||
this.player = this.physics.add.sprite(160, 520, 'squirrel');
|
this.player = this.physics.add.sprite(160, 520, 'player-sheet', 'idle0');
|
||||||
this.player.setScale(1.12);
|
this.player.setScale(0.5);
|
||||||
this.player.setCollideWorldBounds(true);
|
this.player.setCollideWorldBounds(true);
|
||||||
this.player.setDragX(900);
|
this.player.setDragX(900);
|
||||||
this.player.setMaxVelocity(330, 760);
|
this.player.setMaxVelocity(330, 760);
|
||||||
this.player.body.setSize(34, 47);
|
this.player.body.setSize(64, 105, true);
|
||||||
this.player.body.setOffset(12, 7);
|
this.player.body.setOffset(40, 62);
|
||||||
|
this.player.play('squirrel-idle');
|
||||||
}
|
}
|
||||||
|
|
||||||
createCollectibles() {
|
createCollectibles() {
|
||||||
@ -314,28 +472,34 @@ class ForestScene extends Phaser.Scene {
|
|||||||
[3370, 345], [3610, 555], [3800, 440], [4050, 555], [4230, 365],
|
[3370, 345], [3610, 555], [3800, 440], [4050, 555], [4230, 365],
|
||||||
[4470, 555], [4680, 460], [4910, 555], [5100, 370]
|
[4470, 555], [4680, 460], [4910, 555], [5100, 370]
|
||||||
].forEach(([x, y], i) => {
|
].forEach(([x, y], i) => {
|
||||||
const acorn = this.acornGroup.create(x, y, 'acorn');
|
const acorn = this.acornGroup.create(x, y, 'flora-sheet', 'acorn-art');
|
||||||
|
acorn.setScale(0.42);
|
||||||
acorn.setBounce(0.2);
|
acorn.setBounce(0.2);
|
||||||
|
acorn.body.setSize(55, 70, true);
|
||||||
acorn.setData('phase', i * 0.4);
|
acorn.setData('phase', i * 0.4);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mushroomGroup = this.physics.add.group({ allowGravity: true });
|
this.mushroomGroup = this.physics.add.group({ allowGravity: true });
|
||||||
const mushrooms = [
|
const mushrooms = [
|
||||||
[720, 575, 'mushroom-red', 'Scarlet bonnet'],
|
[720, 575, 'mush-red', 'Scarlet bonnet'],
|
||||||
[1700, 360, 'mushroom-purple', 'Amethyst veil'],
|
[1700, 360, 'mush-purple', 'Amethyst veil'],
|
||||||
[2860, 575, 'mushroom-gold', 'Honey lantern'],
|
[2860, 575, 'mush-orange', 'Honey lantern'],
|
||||||
[4170, 370, 'mushroom-red', 'Foxfire cap'],
|
[4170, 370, 'mush-brown', 'Foxfire cap'],
|
||||||
[4860, 575, 'mushroom-purple', 'Moon gill']
|
[4860, 575, 'mush-blue', 'Moon gill']
|
||||||
];
|
];
|
||||||
|
|
||||||
mushrooms.forEach(([x, y, texture, name]) => {
|
mushrooms.forEach(([x, y, frame, name], index) => {
|
||||||
const mushroom = this.mushroomGroup.create(x, y, texture);
|
const mushroom = this.mushroomGroup.create(x, y, 'flora-sheet', frame);
|
||||||
|
const scale = frame === 'mush-blue' ? 0.2 : 0.24;
|
||||||
|
mushroom.setScale(scale);
|
||||||
mushroom.setData('name', name);
|
mushroom.setData('name', name);
|
||||||
mushroom.setBounce(0.1);
|
mushroom.setBounce(0.1);
|
||||||
|
mushroom.body.setSize(mushroom.width * 0.52, mushroom.height * 0.62, true);
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: mushroom,
|
targets: mushroom,
|
||||||
y: y - 6,
|
scaleX: scale * 1.04,
|
||||||
duration: 900 + (x % 400),
|
scaleY: scale * 1.04,
|
||||||
|
duration: 900 + index * 120,
|
||||||
yoyo: true,
|
yoyo: true,
|
||||||
repeat: -1,
|
repeat: -1,
|
||||||
ease: 'Sine.inOut'
|
ease: 'Sine.inOut'
|
||||||
@ -362,15 +526,31 @@ class ForestScene extends Phaser.Scene {
|
|||||||
});
|
});
|
||||||
|
|
||||||
[1120, 2600, 3980].forEach((x, i) => {
|
[1120, 2600, 3980].forEach((x, i) => {
|
||||||
const frog = this.add.image(x, GROUND_Y - 8, 'frog').setOrigin(0.5, 1);
|
const frog = this.add.sprite(x, GROUND_Y - 2, 'fauna-sheet', 'frog0')
|
||||||
|
.setOrigin(0.5, 1)
|
||||||
|
.setScale(0.32)
|
||||||
|
.setDepth(7);
|
||||||
|
frog.play('frog-hop');
|
||||||
|
frog.anims.setProgress((i * 0.27) % 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
[1450, 3450].forEach((x, i) => {
|
||||||
|
const hedgehog = this.add.sprite(x, GROUND_Y - 3, 'fauna-sheet', 'hedgehog0')
|
||||||
|
.setOrigin(0.5, 1)
|
||||||
|
.setScale(0.34)
|
||||||
|
.setDepth(7)
|
||||||
|
.setFlipX(i % 2 === 1);
|
||||||
|
hedgehog.play('hedgehog-walk');
|
||||||
|
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: frog,
|
targets: hedgehog,
|
||||||
y: GROUND_Y - 20,
|
x: x + (i % 2 === 0 ? 190 : -190),
|
||||||
duration: 220,
|
duration: 5200,
|
||||||
delay: 2300 + i * 900,
|
|
||||||
yoyo: true,
|
yoyo: true,
|
||||||
repeat: -1,
|
repeat: -1,
|
||||||
repeatDelay: 3000 + i * 500
|
ease: 'Sine.inOut',
|
||||||
|
onYoyo: () => hedgehog.toggleFlipX(),
|
||||||
|
onRepeat: () => hedgehog.toggleFlipX()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -507,8 +687,7 @@ class ForestScene extends Phaser.Scene {
|
|||||||
if (!this.player?.body) return;
|
if (!this.player?.body) return;
|
||||||
if (this.player.body.blocked.down || this.player.body.touching.down) {
|
if (this.player.body.blocked.down || this.player.body.touching.down) {
|
||||||
this.player.setVelocityY(-520);
|
this.player.setVelocityY(-520);
|
||||||
this.player.setAngularVelocity(this.player.flipX ? -25 : 25);
|
this.player.play('squirrel-jump', true);
|
||||||
this.time.delayedCall(180, () => this.player?.setAngularVelocity(0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,8 +767,17 @@ class ForestScene extends Phaser.Scene {
|
|||||||
const grounded = this.player.body.blocked.down || this.player.body.touching.down;
|
const grounded = this.player.body.blocked.down || this.player.body.touching.down;
|
||||||
if (grounded) {
|
if (grounded) {
|
||||||
this.player.setAngle(0);
|
this.player.setAngle(0);
|
||||||
|
if (Math.abs(this.player.body.velocity.x) > 35) {
|
||||||
|
this.player.play('squirrel-run', true);
|
||||||
|
} else {
|
||||||
|
this.player.play('squirrel-idle', true);
|
||||||
|
}
|
||||||
|
} else if (this.player.body.velocity.y < 0) {
|
||||||
|
this.player.play('squirrel-jump', true);
|
||||||
|
this.player.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5));
|
||||||
} else {
|
} else {
|
||||||
this.player.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.025, -8, 8));
|
this.player.play('squirrel-fall', true);
|
||||||
|
this.player.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.acornGroup.children.iterate(acorn => {
|
this.acornGroup.children.iterate(acorn => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user