I'm working with Canvas and JS, I have a simple physics sim where a ball is added to the canvas and reacts to gravity, collisions and drag.
Currently it can be fired around by dragging (like an elastic band).
function drawSlingshot() {
if (mouse.isDown) {
ctx.beginPath();
ctx.moveTo(ball.position.x, ball.position.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
ctx.closePath();
}
}
Here's my function for drawing a line indicating where the ball will go. It's unfortunately doing the opposite of what's intended. The ball should travel WITH the line and not against it.
Currently I fetch the location of the X and Y of the ball and the X and Y of the
cursor. if one was to mirror the line through the ball, the point I'm looking for would the the x,y of the mirrored line. (see pic below)
Any idea on how I might do this?
First calculate the difference between cursor and ball.
var difference_x = mouse.x - ball.position.x;
var difference_y = mouse.y - ball.position.y;
Then you draw a line between ball position and ball position minus the difference:
ctx.lineTo(ball.position.x - difference_x, ball.position.y - difference_y);
Related
I am in the process of making an arrow that points to an end goal using a canvas in HTML5 and Javascript. I am doing this by finding the x and y coordinates of the player and the end goal, then using Math.atan2() to find the angle. Up to that point everything works flawlessly, but then I get to the point of rendering the arrow at the same angle of the two points. I use ctx.translate() and ctx.rotate() to rotate the canvas accordingly, but it seems like the canvas doesn't rotate the same amount of degrees as I tell it to. For example:
var angles = 90;
ctx.rotate(angles);
but the canvas will rotate MUCH further than I want it to. Any clues as to why the canvas doesnt rotate by degrees and how to fix this? If needed here is the link to my game WIP: https://jsfiddle.net/juinorCPC/0azfu2wp/4/
EDIT:
I should probably also mention that i HAVE tried to rotate by radians and not by degrees, but the issue is that when i use radians, the canvas will rotate much LESS than it is supposed to.
EDIT x2:
I fixed the jsfiddle.
A quick example of the problem im seeing in action for those who cant get the fiddle to work:
Lets say I have a player in the middle of the canvas: (250, 250). I have a goal at another part of the canvas: (325, 125). I get the rotation in degrees: 23.96248897457819. Now i use ctx.rotate (better known as canvas.rotate() ) to rotate the canvas around the mid point (250, 250). The canvas does NOT rotate how i would like it to. IF i use degrees it rotates too much, if i use radians, it rotates too little.
Hola it me again try using this and if it work it work
function angle(playerX, playerY, goalX, goalY) {
var dx = playerX - goalX;
var dy = playerY - goalY;
var theta = Math.atan2(-dy, -dx);
theta *= 180 / Math.PI;
return theta;
}
this is my jsfiddle : http://jsfiddle.net/mrLt1swj/1/
what i did basically is creating an empty sprite and append the arc as it's child like this :
paddle = graphics2.arc(0, 0, 110, game.math.degToRad(0), game.math.degToRad(45), false);
paddleSprite = game.add.sprite(0, 0);
game.physics.enable(paddleSprite, Phaser.Physics.ARCADE);
paddleSprite.anchor.set(0.5);
// Add the graphics to the sprite as a child
paddleSprite.addChild(paddle);
in this case i can use the physics on the arc , but the problem here
is that the arc is basically a polygon shape, second the position of the sprite is at 0,0 and the arc have different coordinate so the collision will not work if the ball hit the arc instead it will work if it hit the empty sprite
how can i set the collision bound of the arc so the collision between the ball and the arc work
is there any possible solution where i can set physics to arc and not use the sprite
For polygon (non-rectangular) collisions you have to use P2 physics instead of Arcade physics.
Or skip proper physics and calculate the collisions yourself: check the ball's position against the arc radius and angle.
I am trying to build a small app where my users can straighten up a tilted face with just 2 clicks
I ask my users to click on the middle of the nose and the middle of the eyebrows of the face within the image.
From there I get 2 points eyebrowMiddle(x1,y1) and noseMiddle (x2,y2).
Is it possible via these 2 points to calculate how much Canvas
rotation I need to have to rotate the image and make the face straight
in relation to the canvas rectangle?
Also, how can I detect and adjust accordingly if the image is tilted
to the left or right?
Here is a more descriptive image to show you what I mean now.
PS:
x1,y1 and x2,y2 are in relation to the canvas perimeter of
course, not the browser window or anything else.
We have tried the line equation such as m = (x2-x1) / (y2-y1) but the
result is always near 1 so I don't think we are following the right
course at the moment.
We don't care if the image looks wrong in the canvas as long as the
face features are parallel in relation to the bottom of the canvas
(they should be looking straight).
To perform such a rotation, you need to decide of the pivot point. Here i choose the eyebrow.
Then you have to choose a point in the target canvas where this pivot point will be hooked. I decided to choose the point at middle x coordinates, and at fourth of the screen in y.
To compute the rotation angle, you have to use atan2, which will nicely give you the angle for a given deltaY / deltaX in between two points ( angle = Math.atan2 ( delta y , delta x ) ) .
Then to draw :
- Translate to the target point.
- rotate by right angle.
- draw the image centering on its pivot.
ET VOILA, it works :-)
function rotate() {
ctx.save();
// go to default center position
ctx.translate(eyeBrowTargetPosition.x, eyeBrowTargetPosition.y);
// compute angle
var yDelta = noseMiddle.y - eyebrowMiddle.y;
var xDelta = noseMiddle.x - eyebrowMiddle.x ;
var angle = Math.atan2 (yDelta ,xDelta);
// compensate for angle
ctx.rotate(angle);
//draw image centering input on eyebrow
ctx.drawImage(face, -eyebrowMiddle.x, -eyebrowMiddle.y);
ctx.restore();
};
jsbin is here :
http://jsbin.com/wavokaku/2/edit?js,output
result with an approximation of the existing green dots :
i am trying to make the game pong ( my math is really bad and i am working on it) and trying to do the bouncing ball part.
I am trying to calculate the out going(reflecting) angel of the ball after hitting the walls or pedals (the walls are always horizontal and the pedals are always vertical)
Here is an image to demonstrate it better :
here is what i tried so far:
var m = (y2-y)/(x2-x);
var angle = (Math.atan(-m)*57.2957795);
How ever this does not seem to work.
Since the obstacles are always vertical or horizontal, you do not need to do any angle calculations.
If you store the ball's position as (x, y) and it's velocity as (vx, vy) you can at each frame compute the next position to (x + vx, y + vy)
To bounce from a horizontal border, just negate vy, to bounce from vertical borders negate vx.
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?
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
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
}
}