Looping with Objects and OOP with JS - JavaScript Basics Part 6

Published May 14, 2019, 7:17 p.m.

In this OOP with JavaScript tutorial, we're going to work with our new Blob object to create a bunch of blobs to all be doing their thing in the canvas. Code up to this point:

<html>
    <body>

        <canvas id="myCanvas" width=200px height=137px style="border:1px solid #000000;"></canvas>

        <script>
            const canvas = document.getElementById('myCanvas');
            const context = canvas.getContext('2d');

            class Blob {
                constructor(color, size){ //this is your init
                    this.x = Math.random() * canvas.width
                    this.y = Math.random() * canvas.height
                    this.color = color
                    this.size = size
                    this.xChange = 1;
                    this.yChange = 1;
                }

                move(){
                    if(this.x >= canvas.width || this.x <= 0){
                        this.xChange *= -1
                      }

                    if(this.y >= canvas.height || this.y <= 0){
                        this.yChange *= -1
                      }

                    this.x += this.xChange;
                    this.y += this.yChange;
                }

                //dont wanna clear per blob draw.
                draw(){
                    context.beginPath();
                    context.arc(this.x, this.y,this.size, 0, 2*Math.PI);
                    context.fillStyle = this.color;
                    context.fill();
                    context.stroke();
                }
            }

            const newBlob = new Blob("green",25)
            newBlob.draw();
            newBlob.move();
            newBlob.draw(); // ...etc.

        </script>
    </body>
</html>

Now, we'd like to create many blobs, and save them to an array. One way we could do this is manually, like defining an arrray at the top near the canvas and context:

            let blobs = new Array();

Then, after our Blob class, we could do something like:

            const newBlob = new Blob("green",25);
            const newBlob2 = new Blob("red",25);
            const newBlob3 = new Blob("blue",25);

            blobs.push(newBlob);
            blobs.push(newBlob2);
            blobs.push(newBlob3);

Then, we could make a quick function for drawing the blobs and moving them:

            function canvasDraw(){
                context.clearRect(0, 0, canvas.width, canvas.height);
                blobs.forEach(function(obj){
                    obj.draw();
                    obj.move();
                })
            }

Notice that, in this function, we are clearing the rectangle. Then, we're making use the forEach loop within javascript. There are quite a few ways to do loops with javascript. One I quite enjoy is the forEach loop. With this loop, you apply it to an iterable, like an array in our case, and do something "forEach" thing in that array. In this case, the "thing" we wish to do is actually a function that we quickly define. In the forEach loop, the "each" is the object... and that object is whatever "each" points to. In our case, we're passing the blobs array that we've populated with blob object. So in this case, that "obj" is a blob! 

So, with each blob, we draw and then move the blob. 

Now, we can set everything in motion with:

            setInterval(function() {
              canvasDraw();
            }, 10);

Giving us: 

This is cool, OBVIOUSLY, but we can do even better here. The blob creation bit is super ugly and not scale-able. We can use a for loop here too. 

Rather than doing

            const newBlob = new Blob("green",25);
            const newBlob2 = new Blob("red",25);
            const newBlob3 = new Blob("blue",25);

            blobs.push(newBlob);
            blobs.push(newBlob2);
            blobs.push(newBlob3);

Let's instead do:

            for (let i = 0; i<5; i++){
                let newBlob = new Blob("green",25);
                blobs.push(newBlob);
            }

This loop might be a little more complicated to look at, but, basically, it's a question of for (THESE_CONDITIONS).

So the conditions are: (let i = 0; i<5; i++), which means:

i starts at zero. while i < 5...and add 1 to i every loop.

For each iteration of the above condition, we do the thing in the curly braces. 

In our case, this is creating the new blob, and pushing it to our array. We could even save a line and just do:

            for (let i = 0; i<5; i++){
                blobs.push(new Blob("green",25));
            }

Now, the only remaining issue is... this only makes green blobs. I'd like an assortment of colors. To do this, let's just make a random choice from an array of options. Up at the top with our other constants, let's add:

const colors = new Array("red","green","blue","yellow","orange","purple","pink");

To pick a random color from this array:

let randColor = colors[Math.floor(Math.random() * colors.length)];

Basically, we're picking a random index in order to pick a random color here. I can look at this code and follow it...but I think this really should be in a function. I know it's simple, but if I am quickly reading through code, I'd have to do more than just glaze over it. To help with this, I am going to just make a function. I think it will help with legibility, but this is definitely coder preference. 

            function randomChoice(arr){
                return arr[Math.floor(Math.random() * arr.length)];
            }

Then we'd just do:

                let randColor = randomChoice(colors)

If we run this, we find that everything works as intended, but I am finding that the blobs are still just a bit too uniformly moving for my tastes. For this reason I would also like to change the xChange and yChange attributes to be:

                    this.xChange = Math.random();
                    this.yChange = Math.random();

 

Full code is now:

<html>
    <body>

        <canvas id="myCanvas" width=200px height=137px style="border:1px solid #000000;"></canvas>

        <script>
            const canvas = document.getElementById('myCanvas');
            const context = canvas.getContext('2d');
            const colors = new Array("red","green","blue","yellow","orange","purple","pink");

            let blobs = new Array();

            class Blob {
                constructor(color, size){ //this is your init
                    this.x = Math.random() * canvas.width
                    this.y = Math.random() * canvas.height
                    this.color = color
                    this.size = size
                    this.xChange = Math.random();
                    this.yChange = Math.random();
                }

                move(){
                    if(this.x >= canvas.width || this.x <= 0){
                        this.xChange *= -1
                      }

                    if(this.y >= canvas.height || this.y <= 0){
                        this.yChange *= -1
                      }

                    this.x += this.xChange;
                    this.y += this.yChange;
                }

                //dont wanna clear per blob draw.
                draw(){
                    context.beginPath();
                    context.arc(this.x, this.y,this.size, 0, 2*Math.PI);
                    context.fillStyle = this.color;
                    context.fill();
                    context.stroke();
                }
            }



            function canvasDraw(){
                context.clearRect(0, 0, canvas.width, canvas.height);
                blobs.forEach(function(obj){
                    obj.draw();
                    obj.move();
                })
            }


            function randomChoice(arr){
                return arr[Math.floor(Math.random() * arr.length)];
            }


            for (let i = 0; i<10; i++){
                let randColor = randomChoice(colors)
                let newBlob = new Blob(randColor,25);
                blobs.push(newBlob);
            }


            setInterval(function() {
              canvasDraw();
            }, 10);

        </script>
    </body>
</html>

Our very satisfying result is now:

 

  • Introduction to programming with JavaScript tutorial

  • Functions and more Canvas - JavaScript Basics Part 2

  • Running functions on an Interval with setInterval - JavaScript basics Tutorial Part 3

  • Conditionals - JavaScript basics Tutorial Part 4

  • Object Oriented Programming in js - JavaScript Basics Part 5

  • Looping with Objects and OOP with JS - JavaScript Basics Part 6
    (currently viewing)