I've recently started programming small canvas games in JavaScript and is trying to wrap my head around Vector 2d math. I understand the very basics of Vectors (like they represent a point in a 2d space with a direction and that you can add, multiply, subtract and rotate them) but I don't understand how to apply vectors when for instance calculating direction and speed of an in-game object.
Check out this game:
http://rem.im/asteroid.html
A great example of a mini game driven by 2d vector math.
The great Seb Lee Delisle is using this JavaScript pseudo class for his vector calculations:
https://github.com/sebleedelisle/JSTouchController/blob/master/js/Vector2.js
I've read some tutorials on vector math but they have a 100% pure mathematical focus and don't describe how to build games with vectors like controlling space ships and bullets.
Can you point me to some tutorials of how to apply vector math in JavaScript games?
Thanks!
You can see the position of an element as a vector (x,y) which also defines a direction going from the coordinate origin (0,0) to this point.
Velocity is the rate of position change per time unit. So for example (1,5) means that with every time unit (let's say per frame) the x coordinate will change by +1 and the y coordinate will change by +5. So the new position will be (x,y)+(1,5) = (x+1, y+5)
Acceleration is the rate of velocity change per time unit. Let's say you have an acceleration of (1,1), then the velocity will change by +1 in x direction and by +1 in y direction.
Example: Current position of your object is (100, 200), its current velocity is (5,0) and the acceleration is (1,1).
Position in frame 0: (100,200), velocity (5,0)
Position in frame 1: (100,200) + (5,0) = (105,200), new velocity (5,0) + (1,1) = (6,1)
Position in frame 2: (105,200) + (6,1) = (111,201), new velocity (6,1) + (1,1) = (7,2)
etc.
Related
I have the following Figure and the equations:
Three Axis for measuring tilt
Equations for measuring tilt
The body on the Figures is a tri-axial accelerometer sensor, which measures accelaration in meters/seconds².
The goal is to calculate the tilt of the following angles using acceleration values:
ρ: angle of the X-axis relative to the ground (orange line);
Φ: angle of the Y-axis relative to the ground (orange line);
θ: angle of the Z-axis relative to the gravity (green line).
Could someone explain how to find equations 1,2 and 3 from the figure above?
Source of the equations and figure: https://www.thierry-lequeu.fr/data/AN3461.pdf
There is another similar and more detailed source that uses the same equations, but I also could not understand how to find them: https://www.analog.com/en/app-notes/an-1057.html
I have already implemented them and it is working, I just want help to understand how to obtain the equations. Here is the code:
let pitch = Math.atan(ax / Math.sqrt((Math.pow(ay,2) + Math.pow(az,2))) );
let roll = Math.atan(ay / Math.sqrt((Math.pow(ax,2) + Math.pow(az,2))) );
let theta = Math.atan(Math.sqrt((Math.pow(ax,2) + Math.pow(ay,2))) /az);
Thanks in advance.
This is the Pythagorean theorem, finding the 2D distance between 0,0 and a point represented by the two numbers given. If we assign that to a new function it may be clearer:
distance(a, b) { return sqrt((pow(a,2) + pow(b,2))) }
Then angles are calculated by using the inverse tangent function with a distance from that function representing one side of the triangle. For example, the pitch in your question divides the x acceleration by the distance between 0,0 and the acceleration in the YZ plane.
pitch = atan(x / distance(y, z))
I'm creating a script that rotates a THREE.js camera arround based on a mobile phones gyroscope input. It's currently working pretty well, except that every time I rotate my phone over a quadrant, the camera will turn 180 degrees instead of continuing as intended. This is the code that I currently use:
private onDeviceOrientation = ( event ) => {
if( event.alpha !== null && event.beta !== null && event.gamma !== null ) {
let rotation = [
event.beta,
event.alpha,
event.gamma
],
this.orientation = new THREE.Vector3(rotation[0], rotation[1], rotation[2]);
this.viewer.navigation.setTarget(this.calcPosition());
}
};
private calcPosition = () => {
const camPosition = this.viewer.navigation.getPosition(),
radians = Math.PI / 180,
aAngle = radians * - this.orientation.y,
bAngle = radians * + this.orientation.z,
distance = this.calcDistance();
let medianX = Math.cos(bAngle) * Math.sin(aAngle);
let medianY = Math.cos(bAngle) * Math.cos(aAngle);
let nX = camPosition.x + (medianX * distance),
nY = camPosition.y + (medianY * distance),
nZ = camPosition.z + Math.sin(bAngle) * distance;
return new THREE.Vector3(nX, nY, nZ);
};
window.addEventListener('deviceorientation', this.onDeviceOrientation, false);
Soafter doing some research I found that I need to use a Quaternion prevent the switchen when going into a new quadrant. I have no experience with Quaternions, so I was wondering what the best way would be to combine the two Vector3's in the code above into a singel Quaternion.
[Edit]
I calculate the distance using this method:
private calcDistance = (): number => {
const camPosition = this.viewer.navigation.getPosition();
const curTarget = this.viewer.navigation.getTarget();
let nX = camPosition.x - curTarget.x,
nY = camPosition.y - curTarget.y,
nZ = camPosition.z - curTarget.z;
return Math.sqrt((nX * nX) + (nY * nY) + (nZ * nZ));from squared averages
};
And I follow the MDN conventions when working with the gyroscope.
[Edit #2]
Turns out I had my angle all wrong, I managed to fix it by calculating the final position like this:
let nX = camPosition.x - (Math.cos(zAngle) * Math.sin(yAngle)) * distance,
nY = camPosition.y + (Math.cos(zAngle) * Math.cos(yAngle)) * distance,
nZ = camPosition.z - (Math.cos(xAngle) * Math.sin(zAngle)) * distance;
Here is the closest I can give you to an answer:
First of all, you don't need a quaternion. (If you really find yourself needing to convert between Euler angles and quaternions, it is possible as long as you have all the axis conventions down pat.) The Euler angle orientation information you obtain from the device is sufficient to represent any rotation without ambiguity; if you were calculating angular velocities, I'd agree that you want to avoid Euler angles since there are some orientations in which the rates of change of the Euler angles go to infinity. But you're not, so you don't need it.
I'm going to try to summarize the underlying problem you're trying to solve, and then tell you why it might not be solvable. 🙁
You are given the full orientation of the device with a camera, as yaw, pitch, and roll. Assuming yaw is like panning the camera horizontally, and pitch is like tilting the camera vertically, then roll is a degree of freedom that doesn't change affect direction the camera is pointing, but it does affect the orientation of the images the camera sees. So you are given three coordinates, where two have to do with the direction the camera is pointing, and one does not.
You are trying to output this information to the camera controller but you are only allowed to specify the target location, which is the point in space that the camera is looking. This is to be specified via three Cartesian coordinates, which you can calculate from the direction the camera is pointing (2 degrees of freedom) and the distance to the target object (one degree of freedom).
So you have three inputs and three outputs, but only two of those have anything to do with each other. The target location has no way to represent the roll direction of the camera, and the orientation of the camera has no way to represent the distance to some target object.
Since you don't have a real target object, you can just pick an arbitrary fixed distance (1, for example) and use it. You certainly don't have anything from which to calculate it... if I follow your code, you are defining distance in terms of the target location, which is itself defined in terms of the distance from the previous step. This is extra work for no benefit at best (the distance drifts around some initial value), and numerically unstable at worst (the distance drifts toward zero and you lose precision or get infinities). Just use a fixed value for distance and make it simple.
So now you probably have a system that points a camera in a direction, but you cannot tell it what the roll angle is. That means your camera controller is apparently just going to choose it for you based on the yaw and pitch angles. Let's say it always picks zero degrees (that would be the least crazy thing it could do). This will cause discontinuities when the roll angle and yaw angle line up (when the pitch is at ±90°): Imagine pointing a physical camera at the northern horizon and yawing around westward, past the western horizon, and settling on the southern horizon. The whole time, the roll angle of the camera is 0°, so there's no problem. But now imagine pointing it at the northern horizon, and pitching upward, past the zenith, and continuing to pitch backward until you are facing the southern horizon. Now the camera is upside down; the roll angle is 180°. But if the camera controller doesn't change the roll angle from 0°, then it will do a nonphysical "flip" right when you pass the zenith. The problem is that there really is no way to synthesize a roll angle based purely on position and not have this happen. We've just demonstrated that there are two ways to move your camera from pointing north to pointing south, where the roll angle is completely different at the end.
So you're stuck, I guess. Well, maybe not. Can you rotate the image from the camera based on the roll angle of the device orientation? That is, add the roll back into the displayed image? If so, you may have a solution. Let's say the roll angle of the camera controller is always at zero. Then you just rotate the image by the desired roll angle (something derived from beta I guess?) and you're done. If the camera controller has some other convention for choosing the roll angle, you will need to figure that out, undo it, and add the roll angle back on.
Without the actual system in front of me I probably can't help you debug your way to a solution. So I think this is where my journey with this question must end. Good luck!
Summary:
You don't need a quaternion
Pick a fixed distance to your simulated target
Add the roll angle by rotating the image before displaying it
Good luck!
I am working on creating a simple snow simulation, but I am failing horribly on the math. Basically, when a snowflake is initialized, it's x position is set randomly somewhere on the svg canvas. Then from there, it falls straight down. It should be simulating a sine wave (the x coordinates should move like a sine wave).
I haven't done trig since last year so i'm a bit rusty. Math.sin() takes radians I believe, so I multiply by 180, then divide by pi to convert to degrees?
Assume x is the current x position of a snowflake, and width is the width of the canvas.
x += (Math.sin(((x/width)*(180/Math.PI)))*width)
It kind of works, but it is all over the place. I have a vague idea of what i'm doing, but I can't seem to push the math from my brain to code.
Here's a JSFiddle:
What am I doing incorrectly?
It should be:
x += A*Math.sin(F*(y/Height)*2*Math.PI);
where A is the amplitude, i.e. how many pixels you want the flake to shift left and right (note that total shift will be 2*A). F is the frequency, or how often you want the flake to shift left and right (I'd set it at random between 2 and 10 for each flake).
I have recently started playing with canvas after seeing how easy it can be. My first project was just to keep a circle in its boundaries as it moves around. I made a few more things involving the movement of circles and now...
I'm currently working on bouncing two circles off of each other when they hit. You can see the example of that here: http://jsfiddle.net/shawn31313/QQMgm/7/
However, I would like to use a little more real world physics. At the moment, when the circles hit each other they just reverse their path.
As shown here:
// Dont be confused, this is just the Distance Formula
// We compare the distance of the two circles centers to the sum of the radii of the two
// circles. This is because we want to check when they hit each other on the surface
// and not the center.
var distance = Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
var r1 = c1.rad;
var r2 = c2.rad;
if (distance < r1 + r2) {
// Change the slope of both circle
// I would like to figure out a more effecience way of bouncing the circles back
// However, I have no idea how to determine the angle the ball was struck,
// and with that information bounce it off at that angle
c1.xi = -c1.xi; // path is reversed
c1.yi = -c1.yi;
c2.xi = -c1.xi;
c2.yi = -c1.yi;
}
However, I would like the circles to go in opposite direction determined by the point and angle of intersection.
I am only in the 9th grade and not sure how the formula for something like this would look. But I know that it is possible because this kind of physics is present in many games. An example would be an 8-ball game. When the balls hit each other, they move across the table according to how the balls hit each other.
I would appreciate any tips on how to do this or if I should wait until I have a stronger understanding of Physics and Math in general.
too bad we can't draw a very simple scheme.
As far as physics is concerned, you know that the total momentum is conserved, see
http://en.wikipedia.org/wiki/Momentum
There is a good illustration and formulas here http://en.wikipedia.org/wiki/Elastic_collision#Two-_and_three-dimensional
You can simplify formulas if the two object have the same weight.
so now, let's consider the reference frame in which c2 is fixed and center in (0,0).
c1 velocity in this reference would be :
c1.xfi=c1.xi-c2.xi
c1.yfi=c1.yi-c2.yi
Now you have a collision when the distance between the two is the sum of radius. Consider the tangent plane of the two circles.
You now have to decompose the velocity of c1 into a tangent component, which is conserved, and a perpendicular (following the line between c1 and c2), which is transfered to c2.
Then you need to go back to your original reference frame.
(sorry i didn't give you the exact formulas but they are on the links I provided)
If I were doing this myself, I would implement the motion using Newtons law of restitution. Essentially this is a coefficient that relates approach and separation speed of 2 particles before/after impact and it has a value that depends on the material properties of your particles.
Your analysis will essentially amount to identifying the point of impact, then breaking down the approach velocities into components that are parallel and perpendicular to the line of centres of the circle at the point of impact.
The momentum of the particles is conserved perpendicular to the line of centres (so the velocities in that direction remain unchanged by the collision) and the law of restitution applies to the velocities parallel to the line of centres. Thus if you fix the coefficient of restitution (it has to be between 0 and 1) to some value of your choice you can use this law to calculate the separation speeds along the line of centres of your particles after collision using the value of the approach speeds.
If your particles are all of the same mass and radius then the calculations become simpler. You can model elastic collisions by setting the coefficient to 1 (this indicates that separation speed of the particles is the same as the approach speed) which is probably the easiest place to start. By changing the value you will see different behaviour between particles after collisions.
Sorry not to be able to write this all down in formula for you, but this is not really the appropriate place for it. Living in the UK I have no idea what "9th grade" is so I can't assess if the above is too advanced for your current level of education. Here in the UK this type of problem would typically be covered at A-level mathematics education level.
Hopefully though it will give you an indication of the terms and topics that you can teach yourself/ research in order to achieve your goal.
EDIT: I dug into the extremely well-documented source code in Decker's link (vector movement demo) and I'm fairly confident I can figure this out working off some of the code there. Thank you all for your help :D
I'm working on movement for a game in javascript. Left and right arrow keys rotate an image of a spaceship while up arrow causes it to accelerate. Using the degree of rotation and the speed, I can calculate movement in terms of x and y with Math.sin() and Math.cos(), but this means that the ship handles like a car. Seeing as it's supposed to be in space, I'd like to make the rotation of the ship only affect its path while accelerating and to take into account the ship's current movement.
I messed around with it a lot and tried dividing the movement into two separate forces, the current direction and speed and the desired direction, but nothing seems even close to how it should feel.
Sorry if that was confusing, here's the simplified code for the original movement:
function main()
{
if(keyStates[39]) // Right arrow pressed?
ship.deg+=8;
if(keyStates[37]) // Left arrow pressed?
ship.deg-=8;
if(keyStates[38]) // Up arrow pressed?
{
if(ship.speed<16)
ship.speed+=1;
}
var shift=getXYshift(ship.deg,ship.speed);
function getXYshift(deg,speed)
{
return {x:Math.round(Math.cos((90-deg)*Math.PI/180)*speed*-1), y:Math.round(Math.sin((90-deg)*Math.PI/180)*speed)};
}
setTimeout(function(){ main() }, 50);
}
You can use one Vector to keep track of the ships speed and direction and alter the direction of that vector when the up arrow is pressed by checking the angle of a second Vector used to keep track of the ships current angle.
I recommend getting this book Supercharged Javascript Graphics which explains in detail the use of vectors and much more.
You can also view the source code for one of the books examples here at the authors website which has a vector handling object that could prove useful to you.
Based on my low physical knowledge:
The ship has a speed with a direction. This can be expressed as a vector from your space, like x pixels on the X-axis, y pixels on the Y-axis (and maybe more dimensions) per second.
Then it has a rotation speed, like α degrees counterclockwise per second.
To compute the travel of your ship for a second, just add the speed vector to the coordinates. And add the rotation to the current orientation.
To change the speed vector based on rotation and acceleration, you would build a vector with a length relating to the acceleration, in the direction of the current orientation. Then add the acceleration vector to the speed vector.
Pseudo code:
ship = {
coordinates: [0, 0], // space units
orientation: 0, // radiant
speed: [0, 0], // space units / time frame
rotation: 0 // radiant / time fram
}
function animatestep {
coordinates[0] += speed[0];
coordinates[1] += speed[1];
orientation += rotation;
}
onaccelerate = function {
speed[0] += cos(orientation) * acceleration;
speed[1] += sin(orientation) * acceleration;
}
onleft = function {
rotation++;
}
onright = function {
rotation--;
}
Note that this makes the space ship really behave like a space ship, because rotation might be difficult to stop. Instead of using a rotation speed, you might need to allow to set the orientation of the ship step-by-step :-) You might also set limits on rotation and acceleration (otherwise the ship bursts) and use a maximum velocity (like the speed of light, including different speed addition).
You should be using a mathematical concept known as a "vector" for your movement. A vector is simply a force and a direction. This vector will be applied to the X,Y coordinate of your ship (ignoring its direction) every frame when determining where to draw the ship. When you accelerate you will use the direction the ship is facing and a constant value assigned to acceleration to form a vector that can be applied to your movement vector for calculating its effect on velocity.
Here is a quick introduction to vectors: http://www.khanacademy.org/science/physics/v/introduction-to-vectors-and-scalars , after watching the video you should have a good idea about what need to be looking for. From there Google should be your friend.
EDIT: Above when I said: "you will use the direction the ship is facing and a constant value assigned to acceleration to form a vector that can be applied to your movement vector for calculating its effect on velocity" I was referring to vector algebra. If you decide to use vectors to solve your problem, you will need to use the concept of vector addition to accelerate. When you press the arrow key, you will generate a vector of magnitude m (where m can be any real number indicating how fast you want to accelerate) and a direction d (more than likely this value will correspond with the direction the ship is facing). You will then add this new vector to the ships current vector to get the ships new vector after the acceleration for the current frame is applied. You can read more here: http://emweb.unl.edu/Math/mathweb/vectors/vectors.html
Cheers and happy Coding
Do you use getXYshift after a right/left arrow press? You should only use it when the up arrow is pressed. This way your ship will rotate without accelerating in any direction. Only change your velocity when the up arrow key is pressed and decelerate when it isn't. Don't change the velocity with the right/left keys, use them to change the rotation of your ship.