Amechi
Amechi

Reputation: 800

cloning a moving ball in javascript on a HTML canvas

Need help with cloning a moving ball in javascript. So the ball inherits the same property and actions of the moving ball when clicking it. I have tried using cloneNode(), using prototype and inheritance. The cloning area within the code is after the comment //Clone prototype and constructor

Here is the full code below and the Demo in JS fiddle at the bottom of this code.

    #balling {
      border:1px solid rgb(0,0,0);
    }

  </style>
</head>
<body>
  <canvas id="balling" width="500" height="400"></canvas>

  <script type="text/javascript">
    var canvas = document.getElementById('balling');
    var context = canvas.getContext('2d');

    // The Properties of the Circle and Position within the Viewport
    var CircleOptions = {
      posBall: {
        x: 160, 
        y: 180
      },
      radius: 40,
      startAngle: 0, 
      endAngle: Math.PI * 2, 
      anticlockwise: false,
      radians: 0,
      xMove: Math.random(),
      yMove: Math.random(),
      speed:2,
      angle:80,
      velocityX:1,
      velocityY:1
    }; 

    //Math to make the ball move
    function moveBall() {
      CircleOptions.radians = CircleOptions.angle * Math.PI/180;
      CircleOptions.xMove = Math.cos(CircleOptions.radians) * CircleOptions.speed * CircleOptions.velocityX;
      CircleOptions.yMove = Math.sin(CircleOptions.radians) * CircleOptions.speed * CircleOptions.velocityY;
    }

    //Function to draw the ball
    function DrawOptions() {

      //Reset Canvas
      context.fillStyle = "white";
      context.fillRect(0, 0, canvas.width, canvas.height);

      //Drawing of the ball
      context.fillStyle = "rgb(142, 68, 173)";
      context.beginPath();
      context.arc(CircleOptions.posBall.x, CircleOptions.posBall.y, CircleOptions.radius, CircleOptions.startAngle, CircleOptions.endAngle, CircleOptions.anticlockwise);
      context.closePath();
      context.fill(); 
    }

    //finding the coordinates of the circle
    function CircleCoordinates() {
      CircleOptions.left = CircleOptions.posBall.x - CircleOptions.radius,
      CircleOptions.right = CircleOptions.posBall.x + CircleOptions.radius,
      CircleOptions.top = CircleOptions.posBall.y - CircleOptions.radius,
      CircleOptions.bottom = CircleOptions.posBall.y + CircleOptions.radius;
    }

    // Animate and call the function to move the ball
    setInterval(Move, 20);

    //Function call for the ball
    moveBall();

    //The function to make it move, reset canvas for movement and color/create shape of ball
    function Move() {
      //Function call for drawing and pinpointing the coordinates
      DrawOptions();
      CircleCoordinates();

      //Power to make it move
      CircleOptions.posBall.x += CircleOptions.xMove;
      CircleOptions.posBall.y += CircleOptions.yMove; 

      //checks for ball hitting the Wall
      if(CircleOptions.posBall.x > canvas.width || CircleOptions.posBall.x < 0) {
        CircleOptions.angle -= 770;
        moveBall();
      } else if(CircleOptions.posBall.y > canvas.height || CircleOptions.posBall.y < 0) {
        CircleOptions.angle -= 2760;
        moveBall();
      } else if(CircleOptions.posBall.y == canvas.height || CircleOptions.posBall.y > canvas.width) {
        CircleOptions.angle += 90;
        moveBall();
      }
    }

    canvas.addEventListener('click', function (e) {
      var clickedX = e.pageX - this.offsetLeft;
      var clickedY = e.pageY - this.offsetTop;

      if (clickedX < CircleOptions.right && clickedX > CircleOptions.left && clickedY > CircleOptions.top && clickedY < CircleOptions.bottom) {
        // alert('Double Me Please!');
        Clone();
      }
    });

    // Clone prototype and constructor
    function Clone() {
      var newCanvas = document.getElementById('balling');
      var context = newCanvas.getContext('2d');

      context.fillStyle = "rgb(142, 68, 173)";
      context.beginPath();
      context.arc(CircleOptions.posBall.x, CircleOptions.posBall.y, CircleOptions.radius, CircleOptions.startAngle, CircleOptions.endAngle, CircleOptions.anticlockwise);
      context.closePath();
      context.fill(); 

      return newCanvas;
    }

    //function call for clone

    //For cursor style in and out element
    canvas.addEventListener('mouseover', function () {
      document.body.style.cursor = "pointer";
    });

    canvas.addEventListener('mouseout', function () {
      document.body.style.cursor = "default";
    });
  </script>

An Updated Fiddle Demo: http://jsfiddle.net/coder101/CMW24/5/

Upvotes: 1

Views: 1824

Answers (1)

KellyCode
KellyCode

Reputation: 797

In your jsFiddle version:

The Clone method and call at the bottom don't do anything.

Your CircleOptions is really not options, it's the object that represents the ball.

Your Move function is the repeating controller that makes it move around.

Your setInterval method is what starts it running by calling Move and uses the existing DrawOptions and CircleOptions; CircleCoordinates doesn't do anything at all.

If you want to clone the ball, you'd want to create an array of CircleOptions objects (change the name) and then loop through them inside Move or they should probably each have their own Move method and act on that. But if it's JavaScript, having them all move within one method would be less processor intensive.

I cleaned up the code and removed the code that didn't do anything. Now I'd make the balls belong to an array and make your click event add more balls. I'll leave that exercise to you.

var canvas = document.getElementById('balling');
var context = canvas.getContext('2d');

var ball = function( new_x, new_y) {
    var b = {};
    b.posBall = {
        x: new_x,
        y: new_y
    };
    b.radius = 40;
    b.startAngle = 0;
    b.endAngle = Math.PI * 2;
    b.anticlockwise = false;
    b.radians = 0;
    b.xMove = Math.random();
    b.yMove = Math.random();
    b.speed = 2;
    b.angle = 80;
    b.velocityX = 1;
    b.velocityY = 1;

    return b;
}

//Function to clear the canvas
function DrawReset() {
    //Reset Canvas
    context.fillStyle = "white";
    context.fillRect(0, 0, canvas.width, canvas.height);
    //Drawing of the ball
    context.fillStyle = "rgb(142, 68, 173)";
    context.beginPath();
    context.arc(CurrentBall.posBall.x, CurrentBall.posBall.y, CurrentBall.radius, CurrentBall.startAngle, CurrentBall.endAngle, CurrentBall.anticlockwise);
    context.closePath();
    context.fill();
}

//Math to make the ball move
function moveBall() {
    CurrentBall.radians = CurrentBall.angle * Math.PI / 180;
    CurrentBall.xMove = Math.cos(CurrentBall.radians) * CurrentBall.speed * CurrentBall.velocityX;
    CurrentBall.yMove = Math.sin(CurrentBall.radians) * CurrentBall.speed * CurrentBall.velocityY;
}

//The function to make it move, reset canvas for movement and color/create shape of ball
function Move() {
    //Function call for drawing and pinpointing the coordinates
    DrawReset();

    //Power to make it move
    CurrentBall.posBall.x += CurrentBall.xMove;
    CurrentBall.posBall.y += CurrentBall.yMove;

    //checks for ball hitting the Wall
    if (CurrentBall.posBall.x > canvas.width || CurrentBall.posBall.x < 0) {
        CurrentBall.angle -= 770;
        moveBall();
    } else if (CurrentBall.posBall.y > canvas.height || CurrentBall.posBall.y < 0) {
        CurrentBall.angle -= 2760;
        moveBall();
    } else if (CurrentBall.posBall.y == canvas.height || CurrentBall.posBall.y > canvas.width) {
        CurrentBall.angle += 90;
        moveBall();
    }
}

canvas.addEventListener('click', function (e) {
    var clickedX = e.pageX - this.offsetLeft;
    var clickedY = e.pageY - this.offsetTop;
    alert(e.pageX + ' ' + e.pageY);

    if (clickedX > CurrentBall.right && clickedX > CurrentBall.left && clickedY > CurrentBall.top && clickedY < CurrentBall.bottom) {
        alert('clicked number ');
    }
});

var CurrentBall = ball(160,180);

// Animate and call the function to move the ball
setInterval(Move, 20);

Upvotes: 1

Related Questions