0

I currently have a bunch of balls(circles) that are bouncing and colliding with eachother inside a box.

Right now they are currently plain green balls. But I want to use a image for this circles.

How can I do this? Here is my render function.

  function render() {
  var ball;
  context.fillStyle = "#008800";
  for (var i = 0; i <balls.length; i++) {
     ball = balls[i];
     ball.x = ball.nextx;
     ball.y = ball.nexty;
     context.beginPath();
     context.arc(ball.x,ball.y,ball.radius,0,Math.PI*2,true);
     context.closePath();
     context.fill();
  }

Any ideas? Is it possible? If not, is there any other methods to achieve bouncing and colliding balls with images?

4

2 回答 2

0

Checkout the drawImage function. This allows you to draw an image at a coordinate point on the canvas. It takes an Image instance as it's first parameter and various other position and cropping values. To quote from the MDN page linked above:

drawImage(image, dx, dy, dw, dh, sx, sy, sw, sh)

image An element to draw into the context; the specification permits any image element (that is, <img>, <canvas>, and <video>). Some browsers, including Firefox, let you use any arbitrary element.

dx The X coordinate in the destination canvas at which to place the top-left corner of the source image.

dy The Y coordinate in the destination canvas at which to place the top-left corner of the source image.

dw The width to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in width when drawn.

dh The height to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in height when drawn.

sx The X coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.

sy The Y coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.

sw The width of the sub-rectangle of the source image to draw into the destination context. If not specified, the entire rectangle from the coordinates specified by sx and sy to the bottom-right corner of the image is used. If you specify a negative value, the image is flipped horizontally when drawn.

sh The height of the sub-rectangle of the source image to draw into the destination context. If you specify a negative value, the image is flipped vertically when drawn.

In your case, you would replace the path drawing function with drawImage.

var img = new Image;
img.onload = function() {
    //You have to make sure the image is loaded first
    //Begin rendering!
    render();
};

img.src = "path/to/your/ball/img.png"

function render() {
  var ball;
  context.fillStyle = "#008800";
  for (var i = 0; i <balls.length; i++) {
     ball = balls[i];
     ball.x = ball.nextx;
     ball.y = ball.nexty;
     context.drawImage(img, ball.x - (img.width/2), ball.y - (img.height/2)); //Make x, y the centerpoint
  }
}
于 2013-09-02T15:10:22.727 回答
0

You can do this three ways:

Method 1 - use pattern to fill the ball

Define the image you want to use as a pattern:

/// create a pattern
var pattern = context.createPattern(img, 'repeat');

Now you can use the pattern as a fill style instead of the green color:

context.fillStyle = pattern;

However, as patterns are always drawn with basis at the coordinate's origo (default 0, 0) you will need to to translate for each move. Luckily not that much extra code:

/// to move pattern where the ball is
context.translate(x, y);

context.beginPath();

/// and we can utilize that for the ball as well so we draw at 0,0
context.arc(0, 0, radius, 0, Math.PI * 2);
context.closePath();

context.fillStyle = pattern;
context.fill();

Now, depending on how you want the move the balls around you may or may not need to translate back for each time.

Here's an online demo showing this approach.

Method 2 - Clip the image to fit the ball with Path clipping

Instead of pattern we can use drawImage to draw the image. However, the problem is that this will draw a square so unless you are creating a ball shaped image which fits on top of your ball with transparent pixels.

You can therefor use clipping to achieve the same as with the pattern method:

Here only a few more lines are needed:

/// define the ball (we will use its path for clipping)
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2);
context.closePath();

/// as we need to remove clip we need to save current satte
context.save(); 

/// uses current Path to clip the canvas
context.clip();

/// draw the ball which now will be clipped
context.drawImage(img, x - radius, y - radius);

/// remove clipping
context.restore();

Here's an online demo of this approach.

Method 3 - Pre-clip the ball as an image

Make a ball in Photoshop or some similar programs and just draw this as an image instead of drawing an arc which you then fill.

You simply draw the ball instead of creating a Path with arc:

drawImage(ballImage, x - radius, y -radius);

If you need to draw in different sizes simply extend the call to:

drawImage(ballImage, x - radius, y - radius, radius, radius);

If performance is critical this is the way to go as this has better performance than the other two approaches but isn't as flexible as them.

If you need a balance between flexibility and performance the clipping approach appear to be the optimal one (this may vary from browser to browser so test).

Here's an online demo with drawImage

于 2013-09-02T18:21:36.710 回答