# Ichthyarchy: The Domain of Fishes

**URL:** <https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913>\
**Category:** Gallery\
**Created:** [September 21, 2022, 12:40pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913 "2022-09-21T12:40:24Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [September 21, 2022, 12:40pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/1 "2022-09-21T12:40:24Z")

</div>

ichthyarchy: The domain of fishes; the fish-world in all of its orders.

Reference:

> **[Ichthyarchy - definition - Encyclo](https://www.encyclo.co.uk/meaning-of-ichthyarchy)**
>
> 1) ichthyarchy The domain of fishes; the fish-world in all of its orders.

Saved .png image:

 ![ichthyarchy](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/e/4/e4aee66d04d4befc9b0081f67de24fa8bc6da9b7.png)

Twelve swimming `Fish` objects are instantiated when the sketch is loaded. For each `Fish`, the initial location, direction of swim, and drawing order are randomly calculated. Small random factors modify the horizontal velocity and vertical drift of each `Fish` as it swims.

Click the sketch to stop and start the animation.

p5.js code:

```auto
new p5((p) => {
  let school = [];
  let anim = true;
  p.setup = () => {
    p.createCanvas(p.windowWidth, p.windowHeight);
    p.noStroke();
    p.ellipseMode(p.CENTER);
    p.textFont("Verdana");
    p.textSize(48);
    p.textAlign(p.CENTER, p.CENTER);
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        200,
        60,
        p.color(128, 255, 128),
        p.random(["left", "right"])
      )
    ); // green
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        160,
        80,
        p.color(128, 128, 255),
        p.random(["left", "right"])
      )
    ); // blue
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        200,
        60,
        p.color(255, 128, 128),
        p.random(["left", "right"])
      )
    ); // red
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        160,
        80,
        p.color(255, 255, 128),
        p.random(["left", "right"])
      )
    ); // yellow
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        200,
        60,
        p.color(255, 128, 255),
        p.random(["left", "right"])
      )
    ); // magenta
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        160,
        80,
        p.color(128, 255, 255),
        p.random(["left", "right"])
      )
    ); // cyan
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        240,
        40,
        p.color(184, 115, 51),
        p.random(["left", "right"])
      )
    ); // copper
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        280,
        40,
        p.color(192, 192, 192),
        p.random(["left", "right"])
      )
    ); // silver
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        240,
        40,
        p.color(255, 215, 0),
        p.random(["left", "right"])
      )
    ); // gold
    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        240,
        40,
        p.color(255, 165, 0),
        p.random(["left", "right"])
      )
    ); // orange

    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        280,
        40,
        p.color(166, 10, 61),
        p.random(["left", "right"])
      )
    ); // cranberry

    school.push(
      new Fish(
        p.random(p.width),
        p.random(p.height),
        240,
        40,
        p.color(128, 128, 0),
        p.random(["left", "right"])
      )
    ); // olive

    p.shuffle(school, true);
    p.background(187, 221, 255);
    for (let i = 0; i < school.length; i++) {
      school[i].render();
    }

    p.fill(0, 64);
    p.text("ichthyarchy", p.width / 2, 48);
  };

  p.draw = () => {
    p.background(187, 221, 255);
    if (anim) {
      for (let i = 0; i < school.length; i++) {
        school[i].swim();
      }
    } else {
      for (let i = 0; i < school.length; i++) {
        school[i].render();
      }
    }
    p.fill(0, 64);
    p.text("ichthyarchy", p.width / 2, 48);
  };

  p.windowResized = () => {
    p.resizeCanvas(p.windowWidth, p.windowHeight);
  };

  class Fish {
    constructor(x, y, bodyLength, bodyHeight, c, chirality) {
      this.x = x;
      this.y = y;
      this.bodyLength = bodyLength;
      this.bodyHeight = bodyHeight;
      this.c = c;
      if (chirality == "right") {
        this.chirality = 1;
      } else {
        this.chirality = -1;
      }
    } // end constructor

    swim() {
      let dx;
      let dy;
      dx = (p.abs(p.randomGaussian() * 2) + 2) * this.chirality;

      dy = p.randomGaussian() / 2;
      // (p.height / 2 - this.y) / 100;
      this.x += dx;
      this.y += dy;
      // horizontal correction
      if (this.x > p.width + this.bodyLength / 2) {
        this.x = -this.bodyLength / 2;
      }
      if (this.x < -this.bodyLength / 2) {
        this.x = p.width + this.bodyLength / 2;
      }
      // vertical correction
      if (this.y > p.height - this.bodyHeight / 2) {
        this.y = p.height - this.bodyHeight / 2 - 1;
      }
      if (this.y < this.bodyHeight / 2) {
        this.y = this.bodyHeight / 2 + 1;
      }
      this.render();
    } // end swim

    render() {
      // Body
      p.noStroke();
      p.fill(this.c);
      p.ellipse(this.x, this.y, this.bodyLength, this.bodyHeight);
      p.triangle(
        this.x - (this.chirality * this.bodyLength) / 16,
        this.y,
        this.x - (this.chirality * this.bodyLength) / 2,
        this.y + this.bodyHeight / 2,
        this.x - (this.chirality * this.bodyLength) / 2,
        this.y - this.bodyHeight / 2
      );
      p.triangle(
        this.x,
        this.y,
        this.x - this.bodyLength / 4,
        this.y - this.bodyHeight / 2,
        this.x + this.bodyLength / 4,
        this.y - this.bodyHeight / 2
      );
      p.triangle(
        this.x,
        this.y,
        this.x - this.bodyLength / 4,
        this.y + this.bodyHeight / 2,
        this.x + this.bodyLength / 4,
        this.y + this.bodyHeight / 2
      );

      p.fill(32);
      p.circle(
        this.x + (this.chirality * this.bodyLength) / 4,
        this.y,
        this.bodyHeight / 8
      );
    } // end render
  } // end class Fish

  const toggleAnimation = () => {
    anim = !anim;
  };
  document.addEventListener("click", toggleAnimation, true);
});

```

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [September 21, 2022, 1:05pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/2 "2022-09-21T13:05:44Z")

</div>

Ahah funny one! 😉

Is there a reason you are using p5 [instance mode](https://github.com/processing/p5.js/wiki/p5.js-overview#instantiation--namespace) instead of directly using them in the global namespace? (which would remove all the `p.` attribute accesses)

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [September 21, 2022, 4:32pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/3 "2022-09-21T16:32:21Z")

</div>

The advantage of using instance mode is that you can have multiple sketches on the same webpage.

If you change the canvas size to 800x600 and copy all the sketch code then paste it below the existing sketch code and run it you will end up with 2 sketches. The only problem is a mouse click anywhere on the webpage will pause the animation in _both_ sketches.

The solution is to add the event handler to the canvas rather than the document and a couple of minor changes to the setup function achieves this

```auto
  p.setup = () => {
    let p5canvas = p.createCanvas(800,600);
    p5canvas.canvas.addEventListener("click", toggleAnimation, true);
    p.noStroke();
    ...

```

Now delete the line

````auto
document.addEventListener("click", toggleAnimation, true);```

````

Now the sketch will _only_ respond to mouse clicks on its _own canvas_ and the two sketches work independently.

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [September 21, 2022, 5:09pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/4 "2022-09-21T17:09:14Z")

</div>

> [@quark](#):
>
> The advantage of using instance mode is that you can have multiple sketches on the same webpage.

For completeness’ sake we can also have multiple global mode sketches as long as they live in separate `<iframe>`:  
[https://developer.Mozilla.org/en-US/docs/Web/HTML/Element/iframe](https://developer.Mozilla.org/en-US/docs/Web/HTML/Element/iframe)

> [@quark](#):
>
> Now the sketch will _only_ respond to mouse clicks on its _own canvas_…

Using a more p5js style, we can call [p5.Element](https://p5js.org/reference/#/p5.Element)::**[mousePressed()](https://p5js.org/reference/#/p5.Element/mousePressed)** method over the [p5.Renderer](https://p5js.org/reference/#/p5.Renderer) object returned by [**createCanvas()**](https://p5js.org/reference/#/p5/createCanvas), and then apply [**noLoop()**](https://p5js.org/reference/#/p5/noLoop) or [**loop()**](https://p5js.org/reference/#/p5/loop) to the sketch inside its callback:

* * *

## Global Mode Version:

```javascript
var paused;

function setup() {
  createCanvas(800, 600).mousePressed(togglePause);
  frameRate(2);
}

function draw() {
  background('#' + hex(~~random(0x1000), 3));
}

function togglePause() {
  if (paused ^= true) noLoop();
  else loop();
}

```

* * *

## Instance Mode Version:

```auto
new p5(p => {
  var paused;

  p.setup = function () {
    p.createCanvas(800, 600).mousePressed(togglePause);
    p.frameRate(2);
  };

  p.draw = function () {
    p.background('#' + p.hex(~~p.random(0x1000), 3));
  };

  function togglePause() {
    if (paused ^= true) p.noLoop();
    else p.loop();
  }
});

```

* * *

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [September 21, 2022, 5:38pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/5 "2022-09-21T17:38:39Z")

</div>

Besides the typical instance mode style, we can also add ES6 modules into the mix:

## “index.html”:

```auto
<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<script type=module src=index.mjs></script>

```

## “index.mjs”:

```auto
import sketch from './sketch.mjs';
new p5(sketch);

```

## “sketch.mjs”:

```auto
export default function sketch(p) {
  p.setup = setup;
  p.draw = draw;

  p.togglePause = togglePause.bind(p);
}

function setup() {
  this.createCanvas(800, 600).mousePressed(this.togglePause);
  this.frameRate(2);
}

function draw() {
  this.background('#' + this.hex(~~this.random(0x1000), 3));
}

function togglePause() {
  if (this.paused ^= true) this.noLoop();
  else this.loop();
}

```

Here’s a more complete online example of using modularized files that displays 12 instances of the same sketch:

[https://Self-Avoiding-Walk-II-CoffeeScript.Glitch.me/pages/4pjs-4q5js-4p5js.html](https://Self-Avoiding-Walk-II-CoffeeScript.Glitch.me/pages/4pjs-4q5js-4p5js.html)

Each 1 can be paused/resumed individually. Besides changing background colors & resetting.

> **[Self Avoiding Walk Ii Coffeescript](https://glitch.com/~self-avoiding-walk-ii-coffeescript)**
>
> https://Discourse.Processing.org/t/converting-coding-challenge-self-avoiding-walk-backtracing-from-p5-js-to-processing-java/35047/19

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [September 21, 2022, 6:35pm UTC](https://discourse.processing.org/t/ichthyarchy-the-domain-of-fishes/38913/6 "2022-09-21T18:35:14Z")

</div>

> [@josephh](#):
>
> Is there a reason you are using p5 [instance mode](https://github.com/processing/p5.js/wiki/p5.js-overview#instantiation--namespace) instead of directly using them in the global namespace?

Thanks to you all for the great comments and information about instance mode.

Some time ago, @micuat got me quite interested in the merits of instance mode. Subsequently, I took it upon myself as a challenge to write some sketches that localized names as much as possible. Such is the case with the current sketch.

In particular, note the first line of the instance mode example in this documentation of `p5()`:

> **[reference | p5.js](https://p5js.org/reference/#/p5/p5)**
>
> p5.js a JS client-side library for creating graphic and interactive experiences, based on the core principles of Processing.

That line is:

```auto
const s = p => {

```

It creates `s` as a global reference to a constant to be passed later to a new `p5` object.

In contrast, for the current sketch I decided to instantiate the value to be passed to the `p5` object anonymously, in addition to the other efforts at name localization. Here’s the first line of that sketch:

```auto
new p5((p) => {

```

I am not suggesting that we must always make every effort to avoid creating global names. But that was one of my goals with the present sketch.
