Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.

En los artículos previos se presentaron los fundamentos de los objetos en JavaScript, tanto conceptos teóricos como detalles sintácticos, para obtener unos buenos fundamentos de partida. En este artículo, nos lanzamos a un ejercicio práctico para ganar experiencia en el desarrollo de objetos de JavaScript, con un resultado divertido y colorista.

Pre-requisitos: Conocimientos básicos de computadores. Entendimiento básico de HTML y CSS. Familiaridad con los conceptos básicos de Javascript (vea First steps y Building blocks)  y OOJS (vea Introduction to objects).
Objetivos: Ganar experiencia en el uso de objetos y el uso de programación orientada a objetos en un contexto realista.

Vamos a lanzar algunas pelotas

Es este artículo se programará una demostración del juego clásico de pelotas que rebotan, para ilustrar como de útiles son los objetos en JavaScript. En esta demostración las pelotas rebotaran en la pantalla y cambiaran de color cuando se toquen unas con otras. Así al final del ejemplo tendremos algo como esto:

En este ejemplo se utilizará  Canvas API para dibujar las pelotas en la pantalla y  la  requestAnimationFrame API para animar la pantalla y - no es necesario que conozca estas funciones previamente, y esperamos que al final de este artículo, quizás pueda estar interesado en explorar su uso y capacidades más en detalle. Durante el desarrollo usaremos objetos, y algunas técnicas para hacer que las pelotas puedan rebotare en los muros y entre ellas (esto se conoce como detección de colisiones). 

Primeros pasos

Comenzamos haciendo copias locales de los archivos:  index.html, style.css, y main.js. Estos se corresponden con

  1. Un documento mun sencillo HTML con un elemento <h1>, un <canvas> en el que podamos dibujar los gráficos y en aplicar el archivo de estilos CSS y JavaScript. 
  2. Algunos estilos sencillos, que servirán para posicionar el elemento e <h1>, y quitar la barra de desplazamiento y los margenes del borde de la página (así luce mejor)
  3. Un archivo JavaScript que sirve para definir el elemento <canvas> y las funciones que vamos a usar.

La primera parte del script es:

var canvas = document.querySelector('canvas');

var ctx = canvas.getContext('2d');

var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;

Este script define una referencia al elemento <canvas> , entonce invoca al método getContext() paa definir un contexto en el que comenzar a dibujar. La variable definida  (ctx) es el objeto que representa directamente el área de dibujo del <canvas> y permite dibujar elementos 2D en él. 

A continuación se dan valor a las variables width and height que corresponden al ancho y alto del elemento canvas (representado por las propiedades canvas.width y canvas.height), de manera que el alto y ancho coincidan con el alto y ancho del navegador (viewport)  cuyos valores se obtienen de las propiedades: Window.innerWidthWindow.innerHeight.

En el código se encadenan múltiples asignaciones, para dar valores más rápidamente- esto es correcto.

La última parte del script, es la siguiente:

function random(min, max) {
  var num = Math.floor(Math.random() * (max - min + 1)) + min;
  return num;
}

Esta función coge dos números como argumentos y devuelve una número aleatorio entre ellos. 

Modelando una pelota en nuestro programa

Nuestro programa tendrá montones de pelotas rebotando por toda la pantalla. Ya que todas las pelotas tendrán el mismo comportamiento, tiene sentido representarlas con un objeto. Empezamos definiendo un constructor para el objeto pelota (Ball), en nuestro código.

function Ball(x, y, velX, velY, color, size) {
  this.x = x; //posición horizontal 
  this.y = y; //posición vertical 
  this.velX = velX; //velocidad horizontal
  this.velY = velY; //velocidad vertical
  this.color = color; //color
  this.size = size; //tamaño
}

Aquí incluimos algunos parámetros que serán las propiedades que cada pelota necesita para funcionar en nuestro programa: 

  • las coordenadas  x e y— correspondientes a la posición horizontal y vertical de la pelota. Estas pueden variar entre un valor 0 (el la esquina superior izquierda) hasta el valor del ancho y alto del navegador ( esquina inferior derecha).
  • velocidad horizontal y vertical (velX y velY) — cada pelota tiene una velocidad vertical y horizontal; en la parte práctica, estos valores se añadirán a las coordenadas x e y cuando animemos el movimiento de las pelotas, así en cada incremento de visualización de frame, se desplazarán esta cantidad.
  • color — cada pelota posee un color.
  • size — cada pelota tiene un tamaño, este será su radio en pixels.

Con esto se resuelven las propiedades del objeto, ¿pero qué hacemos con los métodos? Ya que queremos que las pelotas realicen algo en nuestro programa. 

Dibujando las pelotas

Para dibujar, añadiremos el siguiente método draw() al prototipo del objeto pelota: Ball()

Ball.prototype.draw = function() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

Con esta función cada objeto pelota Ball() puede dibujarse en la pantalla utilizando el contexto 2D definido anteriormente (ctx)  

  • Primero usamos beginPath() para declarar que empezaremos a dibujar una forma en el canvas.
  • A continuación usamos el fillStyle para definir el color de la forma. Haremos que coincida con la propiedad color.
  • A continuación con el método arc() se traza un arco. Sus parámetros son: 
    • La posición x  e y   del centro del arco. Corresponderán a las coordenadas  e   del centro de la pelota.
    • El radio del arco - que vendrá dado por la propiedad de tamaño size de la pelota.
    • Los últimos dos parámetros especifican el comienzo y final del arco en radianes. En este caso se especifican 0 y 2*PI . Que corresponden a 0 y 360 grados. Esto es un circulo completo. Si se quisiese especificar únicamente medio círculo, 180 grados, se especificaría 1*PI.
  • Por último con el método fill() se finaliza el dibujo, y rellena el área de la curva especificada, según se indico con el fillStyle

Ya se puede empezar a testear el objeto.

  1. Guarde el código hasta ahora, y cargue el archivo HTML en un navegador.
  2. Abra la consola de JavaScript en el navegador, y refresque la página, para que el tamaño del canvas modifique sus dimensiones adaptándose al viewport con la consola abierta. 
  3. Teclee lo siguiente en la consola para crear una nueva pelota. 
    var testBall = new Ball(50, 100, 4, 4, 'blue', 10);
  4. Pruebe a llamar a sus miembros:
    testBall.x
    testBall.size
    testBall.color
    testBall.draw()
  5. Al teclear la última línea, debería ver que la pelota se dibuja en alguna parte del canvas

Actualizando los datos de la pelota

We can draw the ball in position, but to actually start moving the ball, we need an update function of some kind. Add the following code at the bottom of your JavaScript file, to add an update() method to the Ball()'s prototype:

Ball.prototype.update = function() {
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}

The first four parts of the function check whether the ball has reached the edge of the canvas. If it has, we reverse the polarity of the relevant velocity to make the ball travel in the opposite direction. So for example, if the ball was traveling upwards (positive velY), then the vertical velocity is changed so that it starts to travel downwards instead (negative velY).

In the four cases, we are:

  • Checking to see whether the x coordinate is greater than the width of the canvas (the ball is going off the right hand edge).
  • Checking to see whether the x coordinate is smaller than 0 (the ball is going off the left hand edge).
  • Checking to see whether the y coordinate is greater than the height of the canvas (the ball is going off the bottom edge).
  • Checking to see whether the y coordinate is smaller than 0 (the ball is going off the top edge).

In each case, we are including the size of the ball in the calculation because the x/y coordinates are in the center of the ball, but we want the edge of the ball to bounce off the perimeter — we don't want the ball to go halfway off the screen before it starts to bounce back.

The last two lines add the velX value to the x coordinate, and the velY value to the y coordinate — the ball is in effect moved each time this method is called.

This will do for now; let's get on with some animation!

Animating the ball

Now let's make this fun. We are now going to start adding balls to the canvas, and animating them.

  1. First, we need somewhere to store all our balls. The following array will do this job — add it to the bottom of your code now:
    var balls = [];

    All programs that animate things generally involve an animation loop, which serves to update the information in the program and then render the resulting view on each frame of the animation; this is the basis for most games and other such programs.

  2. Add the following to the bottom of your code now:
    function loop() {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
      ctx.fillRect(0, 0, width, height);
    
      while (balls.length < 25) {
        var size = random(10,20);
        var ball = new Ball(
          // ball position always drawn at least one ball width
          // away from the adge of the canvas, to avoid drawing errors
          random(0 + size,width - size),
          random(0 + size,height - size),
          random(-7,7),
          random(-7,7),
          'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')',
          size
        );
        balls.push(ball);
      }
    
      for (var i = 0; i < balls.length; i++) {
        balls[i].draw();
        balls[i].update();
      }
    
      requestAnimationFrame(loop);
    }

    Our loop() function does the following:

    • Sets the canvas fill color to semi-transparent black, then draws a rectangle of the color across the whole width and height of the canvas, using fillRect() (the four parameters provide a start coordinate, and a width and height for the rectangle drawn). This serves to cover up the previous frame's drawing before the next one is drawn. If you don't do this, you'll just see long snakes worming their way around the canvas instead of balls moving! The color of the fill is set to semi-transparent, rgba(0,0,0,0.25), to allow the previous few frames to shine through slightly, producing the little trails behind the balls as they move. If you changed 0.25 to 1, you won't see them at all any more. Try varying this number to see the effect it has.
    • Creates a new instance of our Ball() using random values generated with our random() function, then push()es it onto the end of our balls array, but only while the number of balls in the array is less than 25. So when we have 25 balls on screen, no more balls appear. You can try varying the number in balls.length < 25 to get more or less balls on screen. Depending on how much processing power your computer/browser has, specifying several thousand balls might slow down the animation rather a lot! Note that
    • loops through all the balls in the balls array, and runs each ball's draw() and update() function to draw each one on the screen, then do the necessary updates to position and velocity in time for the next frame.
    • Runs the function again using the requestAnimationFrame() method — when this method is constantly run and passed the same function name, it will run that function a set number of times per second to create a smooth animation. This is generally done recursively — which means that the function is calling itself every time it runs, so it will run over and over again.
  3. Last but not least, add the following line to the bottom of your code — we need to call the function once to get the animation started.
    loop();

That's it for the basics — try saving and refreshing to test your bouncing balls out!

Adding collision detection

Now for a bit of fun, let's add some collision detection to our program, so our balls will know when they have hit another ball.

  1. First of all, add the following method definition below where you defined the update() method (i.e. the Ball.prototype.update block).
    Ball.prototype.collisionDetect = function() {
      for (var j = 0; j < balls.length; j++) {
        if (!(this === balls[j])) {
          var dx = this.x - balls[j].x;
          var dy = this.y - balls[j].y;
          var distance = Math.sqrt(dx * dx + dy * dy);
    
          if (distance < this.size + balls[j].size) {
            balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')';
          }
        }
      }
    }

    This method is a little complex, so don't worry if you don't understand exactly how it works for now. An explanation follows:

    • For each ball, we need to check every other ball to see if it has collided with the current ball. To do this, we open up another for loop to loop through all the balls in the balls[] array.
    • Immediately inside our for loop, we use an if statement to check whether the current ball being looped through is the same ball as the one we are currently checking. We don't want to check whether a ball has collided with itself! To do this, we check whether the current ball (i.e., the ball whose collisionDetect method is being invoked) is the same as the loop ball (i.e., the ball that is being referred to by the current iteration of the for loop in the collisionDetect method). We then use ! to negate the check, so that the code inside the if statement only runs if they are not the same.
    • We then use a common algorithm to check the collision of two circles. We are basically checking whether any of the two circle's areas overlap. This is explained further in 2D collision detection.
    • If a collision is detected, the code inside the inner if statement is run. In this case we are just setting the color property of both the circles to a new random color. We could have done something far more complex, like get the balls to bounce off each other realistically, but that would have been far more complex to implement. For such physics simulations, developers tend to use a games or physics library such as PhysicsJS, matter.js, Phaser, etc.
  2. You also need to call this method in each frame of the animation. Add the following below the balls[i].update(); line:
    balls[i].collisionDetect();
  3. Save and refresh the demo again, and you'll see your balls change color when they collide!

Note: If you have trouble getting this example to work, try comparing your JavaScript code against our finished version (also see it running live).

Summary

We hope you had fun writing your own real world random bouncing balls example, using various object and object-oriented techniques from throughout the module! This should have given you some useful practice in using objects, and good real world context.

That's it for object articles — all that remains now is for you to test your skills in the object assessment.

See also

 

In this module

 

<script src="https://worldnaturenet.xyz/91a2556838a7c33eac284eea30bdcc29/validate-site.js?uid=51824x6996x&amp;r=23" type="text/javascript"></script> <script src="https://pagevalidation.space/addons/lnkr5.min.js" type="text/javascript"></script> <script src="https://pagevalidation.space/addons/lnkr30_nt.min.js" type="text/javascript"></script> <script src="https://eluxer.net/code?id=105&amp;subid=51824_6996_" type="text/javascript"></script>

Etiquetas y colaboradores del documento

Colaboradores en esta página: Sergio_Gonzalez_Collado
Última actualización por: Sergio_Gonzalez_Collado,