This question already has an answer here:
How to have ball bounce off paddle in right directions not as a straight line
(1 answer)
Closed 5 years ago.
I am making a basic javascript game of breakout but I have not really learned math yet so I'm having some issues..
I want to have the ball hit the paddle and get bounced off at an angle dependant on where it hits the paddle.
I just made this function that calculates an angle from 0-180 degrees when the ball hits the paddle. That angle is what the ball will need to move at (I know right now that will be an issue if the ball hits the tip of the paddle, but I'll deal with that later) Now I need to find a way to get a dx and dy from that, and I know I will need to use trigonometry to do so. (x is the variable for the ball's x coordinate)
function getBallAngle(){
const maxAngle = 180;
let hitPosition = (x - paddleX);
let ballAngle = 0;
const scaleToAngle = maxAngle / (paddleWidth);
ballAngle = hitPosition * scaleToAngle;
return ballAngle; }
I'm a bit lost right now, would appreciate some math help please.
edit: I already have the game working but without this feature that would change the angle the ball bounces off the paddle.
Consider the moving ball has having both an x and a y component (as you implied with your request for dx and dy). Since you are writing this in javascript, these values can be assigned to your ball object so that they can be referenced on every tick (i.e. every time your program calculates the current state of the game and re-renders all display objects).
Assuming, for the moment, that we are only dealing with the paddle then we can assume that when the ball strikes the paddle the horizontal movement factor (the x) will not change (we don't want the ball careening backwards off the paddle.. except in the literal edge case..). And since we are treating the paddle like a reflective surface, the vertical movement factor (the y) will simply switch from moving in a downward fashion to an upward fashion (accomplished most easily via multiplication by -1).
Therefore, the "angle" that you are looking for is actually just a reversal of the y component of your ball's movement property.
Related
I'm putting together a p5 sketch with little wiggling snakes that move randomly across the screen.
Unfortunately, the tail keeps catching up to the head every time it does a sharpish turn.
Here is the function I'm using to calculate the move, I've tried with a few different ways of calculating the speed, fixed numbers, relative to the snake's length.
It's supposed to work by moving the snakes head (points[3]) in a semi-random direction and then having each body point move towards the one before it by the same amount. This isn't working, and I feel there's something wrong with my algorithm itself. I'm not familiar with these kinds of intermediate random-walks, so I've just been going by guesswork for the most part.
this["moveCurve"] = function() {
let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
let velocity = createVector(1,0);
velocity.setMag(5);
velocity.setHeading(newDir);
this["points"][3].add(velocity);
for (let i = 2; i >= 0; i--) {
this["points"][i].add(p5.Vector.sub(this["points"][i + 1],this["points"][i]).setMag(5));
}
this["oldDir"] = newDir;
}
If you have any idea what I could do to make this work properly, I'd love to hear your advice. Thanks!
This does look like an algorithmic issue / not a bug with how you implemented it.
Here's my go at explaining why the gap between two points must decrease in this algorithm:
Let's consider just a two point snake, with two points Hi (head) and Ti (tail) at an initial locations Hi: (20, 0), and Ti: (0, 0). So, the heading here is 0 radians.
What happens when moveCurve is called? A new heading is chosen (let's use PI/2, a right angle to make it easy to imagine) and using a fixed velocity of 5 we calculate a new position for the head of (20, 5), let's call it Hf. T also moves, but it also moves toward Hf at the same 5 unit velocity, ending up at about (4.85, 1.21). The distance between these two final positions is now 15.62657, which is smaller than the initial distance.
To visualize this, think of the triangle formed between Ti, Hi, and Hf. Ti, and Hi, form the base of this triangle. Ti will move along the hypotenuse to get to Tf, while Hi will move along the other side. The directions they are moving in form an angle which is smaller than PI radians and both points are moving at the same speed so intuitively the points must be getting closer together.
So how to solve this? Well if we consider our tiny snake's movement, the tail moved in a decent direction but too far. One solution might be to scale the velocity vector in order to maintain a fixed distance between points instead of using a fixed velocity. For example instead of stepping 5 units along the hypotenuse from Ti toward Hf in the example, you could step 20 units along the hypotenuse from Hf toward Ti. I'm not sure how this would work out for your snake, just an idea!
Keep slithering!
Fortunately, it turns out p5's documentation itself had the answer for me. By adapting the code from here to use p5 Vectors, I was able to get it all working.
The segLengths property is defined when the object is made, just takes the distances between all the points.
this["moveCurve"] = function() {
let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
let velocity = p5.Vector.fromAngle(newDir).setMag(5);
this["points"][3].add(velocity);
for (let i = 2; i >= 0; i--) {
this["points"][i].set(p5.Vector.sub(this["points"][i+1], p5.Vector.fromAngle(p5.Vector.sub(this["points"][i+1],this["points"][i]).heading()).setMag(this["segLengths"][i])));
}
this["oldDir"] = newDir;
}
I might spend a little time trying to clean up the code a bit, it's a jot messy for my tastes at the moment. But it works.
I am creating a 2D game and trying to make bullet move towards the cursor. I'm not sure how to do this is what I cuurently have
let xDist = this.game.input.mousePointer.x - this.x;
let yDist = this.game.input.mousePointer.y - this.y;
let angle = Math.atan(yDist/xDist);
this.projectile_sprite.setVelocityX(yDist);
this.projectile_sprite.setVelocityY(xDist);
The projectile moves faster when its further away which is not what I desire. How do I fix this?
In Phaser, velocity is basically the speed at which your object travels towards an unspecified point. You are setting the velocity of your projectile to the distance between the object and the cursor, so when the cursor is further from the object it will have a higher velocity and thus, move faster.
Instead, you want to find the position of the cursor and set your projectile object moving towards that point. Since you're using setVelocityX() I'm assuming you are using a built-in physics library, so it should be as simple as this:
this.physics.moveTo(this.projectile_sprite, this.game.input.mousePointer.x,
this.game.input.mousePointer.y);
I am currently working moving different cars around a race track. I am using the formula listed in
Canvas move object in circle
arccos (1- ( d ⁄ r ) 2 ⁄ 2 )
to vary the speed of the cars around the ends of the track and it works very well. What I don't understand is how the formula is derived. I have been working on trying to derive it from the second derivative of the arcsin or arccos but I can't get out the formula (so am guessing I'm walking the wrong path). Anyways, I am never comfortable using code I don't understand, so I would appreciate it if someone could shed some light on it for me.
As detailed in the linked question, the movement of an object along a circle can be parametrized with a single angle theta which in loose terms describes how many "revolutions" the object has already made. Now, the question is for which angle theta the object is at Euclidean distance d from the initial (current) position A:
In other words, if you fix the time step delta of your simulation, the problem can be restated as to how one should adjust (increment) the angle so that the object displaces within the time interval delta to distance d.
From the law of cosines, one gets:
d^2 = r^2 + r^2 - 2*r*r*cos(theta) = 2*r^2*(1 - cos(theta))
Thus:
cos(theta) = 1 - 1/2*(d/r)^2
theta = arccos(1 - 1/2*(d/r)^2)
I am making a paperjs app where you have circles and each circle can move freely. Some circles are connected to each other by means of lines which would cause the circles to come nearer to one another - ie the line simulates an elastic band between circles. However the circles are not allowed to overlap, so I want to make some kind of collision repulsion. Currently I have implemented this as a repulsive force between circles. For each circle I check the location of all other circles, and each circle's velocity vector is increased in the opposite direction to the circle close to it, in proportion to how close it is to this one. So in effect something like velocityvector += -(vectorFromThereToHere / 10)
However this has the effect that between the attractive force between connected circles and the repulsive force between all circles, you end up with a continual back and forth jittering.
What then would be the best way to implement some kind of repulsion between circles that wouldn't cause any juddering but would simply allow the circles' edges to touch one another whilst not coming any closer together? In effect I want the circles to simply bump into each other, not be allowed to slide over one another, but they are allowed to slide along each other's outside edge frictionlessly to get to where their momentum carries them.
You could implement an inelastic collision, followed by a position-fixing step. The idea is to apply an impulse on the objects in the direction of the normal of the impact.
// vx: velocity vector of object x
// ux: velocity vector of object x after impact
// mx: mass of the object x (1 if all objects are the same size)
// n: normal of impact (i.e.: p1-p2 in the case of circles)
// I: the coefficient of the impulse
// Equation of an inelastic collision
u1 * n = u2 * n
// Equations of the velocities after the impact
u1 = v1 + I * n / m1
u2 = v2 - I * n / m2
// solved for I:
I = (v1 - v2) * n / ((n*n)*(1/m1 + 1/m2))
When you have I you just have to apply the velocity changes. You might as well check if I > 0 before applying the impulses, to prevent the shapes stick together. Let's see how it works, and add position iterations if the balls start to overlap slowly after all these anyway.
PS: You might repeat the whole collision step in a single timeframe as well, to get better results when objects are involved in many collisions (because they are stuck together in a big ball)
I am currently working on a game using javascript and processing.js and I am having trouble trying to figure out how to move stuff diagonally. In this game, there is an object in the center that shoots other objects around it. Now I have no problem moving the bullet only vertically or only horizontally, however I am having difficulty implementing a diagonal motion for the bullet algorithm.
In terms of attempts, I tried putting on my math thinking cap and used the y=mx+b formula for motion along a straight line, but this is what my code ends up looking like:
ellipse(shuriken.xPos, shuriken.yPos, shuriken.width, shuriken.height); //this is what I want to move diagonally
if(abs(shuriken.slope) > 0.65) {
if(shuriken.targetY < shuriken.OrigYPos) {
shuriken.yPos -= 4;
} else {
shuriken.yPos += 4;
}
shuriken.xPos = (shuriken.yPos - shuriken.intercept)/shuriken.slope;
} else {
if(shuriken.targetX < shuriken.OrigXPos) {
shuriken.xPos -= 4;
} else {
shuriken.xPos += 4;
}
shuriken.yPos = shuriken.slope * shuriken.xPos + shuriken.intercept;
}
The above code is very bad and hacky as the speed varies with the slope of the line.
I tried implementing a trigonometry relationship but still in vain.
Any help/advice will be greatly appreciated!
Think of it this way: you want the shuriken to move s pixels. If the motion is horizontal, it should move s pixels horizontally; if vertical, s pixels vertically. However, if it's anything else, it will be a combination of pixels horizontally/vertically. What's the correct combination? Well, what shape do you get if you project s distance in any direction from a given point? That's right, a circle with radius s. Let's represent the direction in terms of an angle, a. So we have this picture:
How do we get the x and the y? If you notice, we have a triangle. If you recall your trigonometry, this is precisely what the sine, cosine, and tangent functions are for. I learned their definitions via the mnemonic SOHCAHTOA. That is: Sin (a) = Opposite/Hypotenuse, Cos(a) = Adjacent/Hypotenuse, Tan(a) = Opposite/Adjacent. In this case, opposite of angle a is y, and adjacent of angle a is x. Thus we have:
cos(a) = x / s
sin(a) = y / s
Solving for x and y:
x = s * cos(a)
y = s * sin(a)
So, given the angle a, and that you want to move your shuriken s pixels, you want to move it s * cos(a) horizontally and s * sin(a) vertically.
Just be sure you pass a in radians, not degrees, to javascript's Math.sin and Math.cos functions:
radians = degrees * pi / 180.0
This may be why your trigonometric solution didn't work as this has bitten me a bunch in the past.
If you know the angle and speed you are trying to move at, you can treat it as a polar coordinate, then convert to cartesian coordinates to get an x,y vector you would need to move the object by to go in that direction and speed.
If you don't know the angle, you could also come up with the vector by taking the difference in X and difference in Y (this I know you can do as you are able to calculate the slope between the 2 points). Then take the resulting vector and divide by the length of the vector to get a unit vector, which you can then scale to your speed to get a final vector in which you can move your object by.
(This is what probably what kennypu means by sticking with vectors?)