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: update fish-pond tutorial #104

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export function addBackground(app)
// Create a background sprite.
const background = Sprite.from('background');

// Center background sprite anchor.
background.anchor.set(0.5);
// Add the background to the stage.
app.stage.addChild(background);

/**
* If the preview is landscape, fill the width of the screen
Expand All @@ -28,9 +28,7 @@ export function addBackground(app)
}

// Position the background sprite in the center of the stage.
background.anchor.set(0.5);
background.x = app.screen.width / 2;
background.y = app.screen.height / 2;

// Add the background to the stage.
app.stage.addChild(background);
}
5 changes: 3 additions & 2 deletions src/tutorials/v8.0.0/fishPond/step2/step2-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ Now lets fill the pond with some rocks and pebbles, shall we? Let's work inside

## Create and Setup Background Sprite

We already preloaded the pond background asset as the alias 'background' so we can just simply create a sprite
We already preloaded the pond background asset as the alias 'background' so we can just simply create a sprite and add it to the stage.

```javascript
const background = Sprite.from('background');

background.anchor.set(0.5);
app.stage.addChild(background);
```

## Fit and Position Sprite
Expand All @@ -36,6 +36,7 @@ When we manually set the width or height on a sprite, it will apply a scale on t
Then we simply position it at the center of the preview.

```javascript
background.anchor.set(0.5);
background.x = app.screen.width / 2;
background.y = app.screen.height / 2;
```
Expand Down
12 changes: 8 additions & 4 deletions src/tutorials/v8.0.0/fishPond/step3/addFishes-completed.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Container, Sprite } from 'pixi.js';

export function addFishes(app, fishes)
export function addFishes(app)
{
// Create a container to hold all the fish sprites.
const fishContainer = new Container();
Expand All @@ -10,6 +10,7 @@ export function addFishes(app, fishes)

const fishCount = 20;
const fishAssets = ['fish1', 'fish2', 'fish3', 'fish4', 'fish5'];
const fishes = [];

// Create a fish sprite for each fish.
for (let i = 0; i < fishCount; i++)
Expand Down Expand Up @@ -41,6 +42,9 @@ export function addFishes(app, fishes)
// Add the fish sprite to the fish array.
fishes.push(fish);
}

// Return the fish array.
return fishes;
}

export function animateFishes(app, fishes, time)
Expand All @@ -57,11 +61,11 @@ export function animateFishes(app, fishes, time)
fishes.forEach((fish) =>
{
// Animate the fish movement direction according to the turn speed.
fish.direction += fish.turnSpeed * 0.01;
fish.direction += fish.turnSpeed * 0.01 * delta;

// Animate the fish position according to the direction and speed.
fish.x += Math.sin(fish.direction) * fish.speed;
fish.y += Math.cos(fish.direction) * fish.speed;
fish.x += Math.sin(fish.direction) * fish.speed * delta;
fish.y += Math.cos(fish.direction) * fish.speed * delta;

// Apply the fish rotation according to the direction.
fish.rotation = -fish.direction - Math.PI / 2;
Expand Down
2 changes: 1 addition & 1 deletion src/tutorials/v8.0.0/fishPond/step3/addFishes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Container, Sprite } from 'pixi.js';

export function addFishes(app, fishes)
export function addFishes(app)
{
/** -- INSERT CODE HERE -- */
}
Expand Down
6 changes: 2 additions & 4 deletions src/tutorials/v8.0.0/fishPond/step3/step3-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ import { addFishes, animateFishes } from './addFishes';
// Create a PixiJS application.
const app = new Application();

// Store an array of fish sprites for animation.
const fishes = [];

async function setup()
{
// Intialize the application.
Expand Down Expand Up @@ -42,7 +39,8 @@ async function preload()
await preload();

addBackground(app);
addFishes(app, fishes);

const fishes = addFishes(app);

// Add the fish animation callback to the application's ticker.
app.ticker.add((time) => animateFishes(app, fishes, time));
Expand Down
18 changes: 11 additions & 7 deletions src/tutorials/v8.0.0/fishPond/step3/step3-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ const fishContainer = new Container();
app.stage.addChild(fishContainer);
```

Then we declare some reference variables like how many fishes should there be in the pond and what are the fish types available. For the types, we refer to the 5 different fish assets we have preloaded earlier and made them into an array of aliases.
Then we declare some reference variables like how many fishes should be there in the pond and what are the fish types available. For the types, we refer to the 5 different fish assets we have preloaded earlier and made them into an array of aliases.

```javascript
const fishCount = 20;
const fishAssets = ['fish1', 'fish2', 'fish3', 'fish4', 'fish5'];
```

Instead of creating each of the fish individually, which will be super tedious, we will use a simple `for` loop to create each of the fish until it reaches our desire count, also cycling through the fish asset aliases array. In addition to the basic setup and applying initial transforms, we also assign them with custom properties like `direction`, `speed` and `turnSpeed` which will be used during the animation. We will store the fishes in a reference array defined outside of the IIFE.
Instead of creating every fish individually, which would be super tedious, we will use a simple `for` loop to create each of the fishes and store them in an array until it reaches our desired count. In addition to the basic setup and applying initial transforms, we also assign them with custom properties like `direction`, `speed` and `turnSpeed` which will be used during the animation.

```javascript
const fishes = [];

for (let i = 0; i < fishCount; i++)
{
const fishAsset = fishAssets[i % fishAssets.length];
Expand All @@ -40,13 +42,15 @@ for (let i = 0; i < fishCount; i++)
fishContainer.addChild(fish);
fishes.push(fish);
}

return fishes;
```

## Animate Fishes

It's time to give the fishes some movements! Another function `animateFishes` has been prepared and connected to the application's ticker which will be continuously called. It is supplied with a Ticker object which we can use to infer the amount of time passed between the calls.
It's time to give the fishes some movements! Another function `animateFishes` has been prepared and connected to the application's ticker which will be continuously called.

We will declare a few variables to help us with the animation. We extract `deltaTime` from the Ticker object which tells us the amount of time passed since last call, in seconds. We also define an imaginary bound that is larger than the stage itself to wrap the position of the fishes when they go off the screen. We use this bound instead of the actual screen size to avoid having the fishes disappear before they actually go off the edges, since the fish sprites' anchor is in the center so, eg. when a `fish.x = 0`, half of the fish's width is still apparent on the screen.
We will declare a few variables to help us with the animation. We extract `deltaTime` from the Ticker object which tells us the amount of time passed since last call. Using it guarantees consistent movement, regardless of the frame rate. We also define an imaginary bound that is larger than the stage itself to wrap the position of the fishes when they go off the screen. We use this bound instead of the actual screen size to avoid having the fishes disappear before they actually go off the edges, since the fish sprites' anchor is in the center so, eg. when a `fish.x = 0`, half of the fish's width is still apparent on the screen.

```javascript
const delta = time.deltaTime;
Expand All @@ -61,9 +65,9 @@ We can then simply loop through individual fishes array and update them one by o
```javascript
fishes.forEach((fish) =>
{
fish.direction += fish.turnSpeed * 0.01;
fish.x += Math.sin(fish.direction) * fish.speed;
fish.y += Math.cos(fish.direction) * fish.speed;
fish.direction += fish.turnSpeed * 0.01 * delta;
fish.x += Math.sin(fish.direction) * fish.speed * delta;
fish.y += Math.cos(fish.direction) * fish.speed * delta;
fish.rotation = -fish.direction - Math.PI / 2;

if (fish.x < -stagePadding)
Expand Down
10 changes: 5 additions & 5 deletions src/tutorials/v8.0.0/fishPond/step4/addWaterOverlay-completed.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { Texture, TilingSprite } from 'pixi.js';

// Reference to the water overlay.
let overlay;

export function addWaterOverlay(app)
{
// Create a water texture object.
const texture = Texture.from('overlay');

// Create a tiling sprite with the water texture and specify the dimensions.
overlay = new TilingSprite({
const overlay = new TilingSprite({
texture,
width: app.screen.width,
height: app.screen.height,
});

// Add the overlay to the stage.
app.stage.addChild(overlay);

// Return the water overlay.
return overlay;
}

export function animateWaterOverlay(app, time)
export function animateWaterOverlay(overlay, time)
{
// Extract the delta time from the Ticker object.
const delta = time.deltaTime;
Expand Down
5 changes: 1 addition & 4 deletions src/tutorials/v8.0.0/fishPond/step4/addWaterOverlay.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Texture, TilingSprite } from 'pixi.js';

// Reference to the water overlay.
let overlay;

export function addWaterOverlay(app)
{
/** -- INSERT CODE HERE -- */
}

export function animateWaterOverlay(app, time)
export function animateWaterOverlay(overlay, time)
{
/** -- INSERT CODE HERE -- */
}
10 changes: 4 additions & 6 deletions src/tutorials/v8.0.0/fishPond/step4/step4-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { addWaterOverlay, animateWaterOverlay } from './addWaterOverlay';
// Create a PixiJS application.
const app = new Application();

// Store an array of fish sprites for animation.
const fishes = [];

async function setup()
{
// Intialize the application.
Expand Down Expand Up @@ -43,13 +40,14 @@ async function preload()
await preload();

addBackground(app);
addFishes(app, fishes);
addWaterOverlay(app);

const fishes = addFishes(app);
const overlay = addWaterOverlay(app);

// Add the animation callbacks to the application's ticker.
app.ticker.add((time) =>
{
animateFishes(app, fishes, time);
animateWaterOverlay(app, time);
animateWaterOverlay(overlay, time);
});
})();
14 changes: 9 additions & 5 deletions src/tutorials/v8.0.0/fishPond/step4/step4-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,26 @@ Here we create a tiling sprite, supplying a texture and dimensions as an option
```javascript
const texture = Texture.from('overlay');

overlay = new TilingSprite({
const overlay = new TilingSprite({
texture,
width: app.screen.width,
height: app.screen.height,
});

app.stage.addChild(overlay);

return overlay;
```

## Animate Overlay

Similar to the previous step, we will now animate the water overlay using the application's ticker. The code has been modify to call both animation functions for the fish and this overlay so we only need to add the animation logic inside the `animateWaterOverlay` function.
Similar to the previous step, we will now animate the water overlay using the application's ticker. The code has been modified to call both animation functions for the fish and overlay, so now we only need to add the animation logic inside the `animateWaterOverlay` function.

```javascript
elapsed += time.deltaTime;
overlay.tilePosition.x = elapsed * -1;
overlay.tilePosition.y = elapsed * -1;
const delta = time.deltaTime;

overlay.tilePosition.x -= delta;
overlay.tilePosition.y -= delta;
```

Congratulations, we have now completed a beautiful pond! But we can take it a step further. Let's proceed to the final touch!
11 changes: 5 additions & 6 deletions src/tutorials/v8.0.0/fishPond/step5/step5-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import { addDisplacementEffect } from './addDisplacementEffect';
// Create a PixiJS application.
const app = new Application();

// Store an array of fish sprites for animation.
const fishes = [];

async function setup()
{
// Intialize the application.
Expand Down Expand Up @@ -44,14 +41,16 @@ async function preload()
await preload();

addBackground(app);
addFishes(app, fishes);
addWaterOverlay(app);

const fishes = addFishes(app);
const overlay = addWaterOverlay(app);

addDisplacementEffect(app);

// Add the animation callbacks to the application's ticker.
app.ticker.add((time) =>
{
animateFishes(app, fishes, time);
animateWaterOverlay(app, time);
animateWaterOverlay(overlay, time);
});
})();
11 changes: 5 additions & 6 deletions src/tutorials/v8.0.0/fishPond/step6/step6-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import { addDisplacementEffect } from './addDisplacementEffect';
// Create a PixiJS application.
const app = new Application();

// Store an array of fish sprites for animation.
const fishes = [];

async function setup()
{
// Intialize the application.
Expand Down Expand Up @@ -44,14 +41,16 @@ async function preload()
await preload();

addBackground(app);
addFishes(app, fishes);
addWaterOverlay(app);

const fishes = addFishes(app);
const overlay = addWaterOverlay(app);

addDisplacementEffect(app);

// Add the animation callbacks to the application's ticker.
app.ticker.add((time) =>
{
animateFishes(app, fishes, time);
animateWaterOverlay(app, time);
animateWaterOverlay(overlay, time);
});
})();