Animation with Initial Velocity - javascript

I've been trying to solve this problem for a number of days now but I must be missing something.
Known Variables:
vi = Initial Velocity
t = Animation Duration
d = Distance.
end velocity should always be zero
The function I'm trying to create: D(0...t) = the current distance for a given time
Using this information I want to be able to create a smooth animation curve with varying velocity (ease-in/ease-out).
The animation must be able ease-in from an initial velocity.
The animation must be exactly t seconds and must be travel exactly d units.
The curve should lean towards the average velocity with acceleration occurring at the beginning and the end portions of the curve.
I'm open to extra configuration variables.
The best I've been able to come up with is something that doesn't factor in the initial velocity. I'm hoping someone smarter can help me out. ;)
Thank you!
p.s. I'm working with an ECMAScript variant

Here is a different solution, where there isn't any time interval where the velocity is constant. Instead, velocity as a function of time is a second-order polynomial, and the acceleration is linear in time (positive at the beginning, and negative at the end). Maybe you can try it.
Let me rename your variables a bit. Let
T = final time = animation duration
V = initial velocity (>0)
D = total distance (>0)
We are searching for a smooth function v(t) (velocity as a function of time) such that:
v(0) = V
v(T) = 0
the integral from 0 to T of v(t)dt is D
With a (concave) second-order polynomial we can satisfy all the three constraints. Hence, let
v(t) := at^2 + bt + c
and let's solve for a, b, c. The first constraint v(0) = V gives immediately c = V.
The second constraint reads
aT^2 + bT + V = 0
On the other hand, the integral of v(t) is d(t) = 1/3 a t^3 + 1/2 b t^2 + Vt (this is the distance covered up to time t), hence the third constraint reads
d(T) = 1/3 a T^3 + 1/2 b T^2 + VT = D
The last two equations seem messy, but they are just two linear equations in the two unknowns a, b, and they should be easily solvable. If I did my computations correctly, the final result is
a = 3V/T^2 - 6D/T^3, b = 6D/T^2 - 4V/T
If you substitute a, b, c in the expression of d(t), you obtain the covered distance as a function of time.

I believe you want to solve your problem in 3 parts.
First, you need to solve for the minimum velocity necessary to complete the distance in time T.
This would be pretty simple (D/t) = v(min)
It assumes instantaneous acceleration from v(initial) to v(min) and again deceleration over a time period of 0s at the beginning and end.
so for example say your v(i) is 5px/s.
you want a 100px movement over 10 seconds.
v(min) = 100px/10s = 10px/s
Second, you want a smooth acceleration from v(initial) to v(min). this will take some period of time t(acc). Assuming the acceleration and deceleration will be equal, then you can just figure for one of them, then multiply by 2.
We can call the function that describes the distance travelled during accelleration D(accel).
Lets keep it easy to start and say we want the duration of accelleration to be 1s
so your equation for total distance travelled is going to be
D(total) = D(accel) + D(v(max) )
When you know that D(accel) is for 2s total, you can calculate
D(accel) = ( V(ini) + V(max) ) /2) * (2seconds)
and
D(v(max)) = V(max) * 8s
solving for V(max) we get
100px = D(accel) + D(v(max))
100px = ( 5px/s + VMax) /2 *(2s)) + VMax *8s
100px = 5px + (Vmax * 1s) + Vmax *8s
95px = 9Vmax *s
VMax = 95px/9s
VMax = 10.556px/s
You can now go back and replace your 1s acceleration window with a formula that defines the acceleration window as a % of the overall time period or some other thing.
Also note that for animation purposes, you will have to break 10.556px/s down into per frame px movements and account for time appropriately.

abustin, since you don't like the 3 segment solution, you may want to try looking at Bezier curves to solve this problem. Bezier curve can be utilized to interpolate time as well as distance, so you can define a few control points near the ends of your motion to generate acceleration, where the middle "segment" will be defined such that the velocity is close to constant. Utilizing splines is a possibility too.

Using constant accelerations:
Definitions:
Vi - Initial velocity
Va - Average velocity
Vo - Ending velocity
D - Total distance to be traveled
T - Total time for travel
t1 - Acceleration time from beginning to Va
t2 - Acceleration time from Va to Vo
The equation to solve is:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
You should decide how much time the initial acceleration (t1) and the final acceleration (t2) takes and then you are left with only one unknown -> Va, which can be easily solved.
EDIT: find the distance as a function of time:
Well, now that you know the velocities, it is easy to figure out the distance traveled:
D(t) = Vi*t + 0.5*t^2*(Va-Vi)/t1 {0<t<t1}
D(t) = Va*(t-t1) + D1 {t1<t<t3}
D(t) = Va*(t-t3)+0.5*(t-t3)^2*(Vo-Va)/t2 + D2 {t3<t<T}
where t3=(T-t2), D1 and D2 are the distance traveled at the end of the first and second segments, which can be found from the respective functions:
D1 = 0.5*(Va+Vi)*t1
D2 = D1 + Va*(t3-t1)
EDIT 2: Solving for Va:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
Remember that t1 and t2 are the problem parameters that you choose. You decide what fraction of the movement the object accelerates and decelerates. Let's say t1=t2=0.1*T. Substitution then gives:
(Vi+Va)/2*(0.1T) + Va*(T-(0.1T)-(0.1T)) + (Va+Vo)/2*(0.1T) = D
Va*(0.1T/2 + T-0.1T-0.1T + 0.1T/2) + Vi*(0.1T)/2 + Vo*(0.1T)/2 = D
Va*(0.9T) + Vi*(0.05T) + Vo*(0.05T) = D
Va*(0.9T) = D - Vi*(0.05T) + Vo*(0.05T)
Va = (D - (Vi + Vo)*(0.05T)) / (0.9T)
Got it?

Federico's solution is a nice one, but I found the acceleration of a linear acceleration solution a bit too abrupt, and I ended up forging ahead with a double parabola solution where the acceleration is constant, first in one direction and then in the other, until the object ends at 1 with a velocity 0. (I did try solving it with variable starts and ends, but it was too difficult. Instead, my implementation just scales the inputs and outputs before passing them through the function.)
The math was high school stuff, but I'll go over it for completeness' sake.
given v, the initial velocity, we have two parabolas, the left and the right
ly = m(t - ax)^2 + ay, where t is the time input, ranging from 0 to 1, and ax, ay, and m are constants we need to find, given v.
ry = -m(t - 1)^2 + 1
Note, they both take m as their steepness, because they accelerate at the same rate. ry uses -m because it accelerates in the other direction.
We have a number of constraints to solve for
ly(0) = 0, the value is 0 at t = 0
ly'(0) = v, the differential of the equation(the velocity) is v(the initial velocity, given) at t = 0
ly(h) = ry(h), the two parabolas connect at some given halfway point (which is not actually halfway unless v = 0)
ly'(h) = ry'(h), the velocity is the same at that halfway point, no sudden jerks
I went through a number of approaches from here on out, but in the end it seemed that the only way was to solve for m in terms of v. We arrive at the formula mm + m(v - 2) - (vv)/4. Applying the quadratic formula, we get m = ((2 - v) ± sqrt(2vv - 4v + 4))/2
Meaning that either
m = ((2 - v) + sqrt(2v*v - 4v + 4))/2
or
m = ((2 - v) - sqrt(2v*v - 4v + 4))/2
And we find that we can decide which it is by looking at the initial velocity,
let sqrt_part = Math.sqrt(2*sq(initial_velocity) - 4*initial_velocity + 4)
let m = (2 - initial_velocity + (initial_velocity < 2 ? sqrt_part : -sqrt_part))/2
from there, the rest of the variables (ax, ay and h) are quite easy to work out.
There is a rust implementation of the formulai here https://gist.github.com/makoConstruct/df173c3a4e0854b535869fdc2acdeeb1
Rust's syntax is pretty ordinary, so you wont have much trouble translating that to JS. Feel free to post your port in the comments.

Related

How to represent this vector algebra for 2d point calculation using comma notation in a typical programming language?

I reached out for help recently on math.stackexchange.com with a question about 2 dimensional algebra. The answer was promptly provided but it's in mathematical notation unfamiliar to me and the person giving the answer has stopped responding to my questions. While I am extremely grateful to BStar for providing this information, he/she has stopped replying both on the site and the chat, and doesn't seem interested in helping me understand it to the point that I could write programming code to calculate the desired point P. I respect that, but it leaves me stuck for now. Could someone help me convert this sequence of steps into a programming language such as Javascript? (I am actually working in PHP, but Javascript would be more convenient to represent in a runnable Snippet on stackoverflow .. I'm happy with any current language that I can translate into PHP).
The post is at https://math.stackexchange.com/questions/4110517/trig-101-calculate-coords-of-point-p-such-that-it-is-distance-n-from-line-ab-an/4110550?noredirect=1#comment8504010_4110550
The answer given is in Latex but here's a screenshot of it:
The latest description of the process by the author BStar: "Here is the process: First calculate cos B and use arccos to get B. Second calculate tanθ to get θ with arctan by using |BP| is the same from two triangles. Knowing these, we can get vectors BA’ and B’P, thus vectors OA and OP. We get θ to grt vector BA’ in this case, not the other way around. "
I can follow up until step (5) where the comma notation comes in, i.e. k = (-xb, -yb)(xc - xb, yc - yb) / ac. This seems to make k a two dimensional vector but I don't think I ever worked with this notation. Later, k is used in step (6) and (6a) to calculate theta, appearing both in the numerator and denominator of a fraction. I have no idea how to expand this to get an actual value for theta.
(Edit Note: The author BStar assumed point A is at the origin, so (xa, ya) = (0, 0) but I cannot make that assumption in the real world. Thus the vector BA in Step 1 is actually (xa - xb, ya - yb) and his formula for k shown above is actually k = (xa - xb, ya - yb)(xc - xb, yc - yb) / ac. This expansion needs to be carried through the calculation but it's not a major change.)
If we were to frame this in Javascript, I could lay out a framework of what is known at the beginning of the calculation. It's not productive to represent every single step of the mathematical proof given by BStar, but I'm not sure exactly what steps can be left as processes in the mathematical proof and what steps need expounding in code.
/* Known points - A, B, C */
var xa = 10, ya = 10;
var xb = 100, yb = 500;
var xc = 700, yc = 400;
/* Known lengths m and n (distance perpendicularly from AB and AC) */
var m = 30;
var n = 50;
/* Point we want to calculate, P */
var px = 0, py = 0;
/* Calculation goes here - some Javascript notes:
* var a = Math.sin(angInRadians);
* var b = Math.asin(opposite / hypotenuse);
* var c = Math.pow(number, 2); // square a number
* var d = Math.sqrt(number);
*/
/* Print the result */
console.log('Result: P (' + px + ', ' + py + ')');
How would one express the maths from the diagram in the programming snippet above?
I think I can get you to the angle of B but I'm not very good with math and get lost with all those variables. If you are stuck at figuring out the angle try this and see if it does what you want. It seems to do what step 5 is asking but double check my work.
let pointA = {x: 100, y: 0};
let pointB = {x: 20, y: 20};
let pointC = {x: 0, y: 100};
let distBA_x = pointB.x - pointA.x;
let distBA_y = pointB.y - pointA.y;
//let BA_a = Math.sqrt(distBA_x*distBA_x + distBA_y*distBA_y);
let distBC_x = pointB.x - pointC.x;
let distBC_y = pointB.y - pointC.y;
//let BC_c = Math.sqrt(distBC_x*distBC_x + distBC_y*distBC_y);
var angle = Math.atan2(distBA_x * distBC_y - distBA_y * distBC_x, distBA_x * distBC_x + distBA_y * distBC_y);
if(angle < 0) {angle = angle * -1;}
var degree_angle = angle * (180 / Math.PI);
console.log(degree_angle)
I've laid it out on a canvas so you can see it visually and change the parameters. Hope it helps. Here's the Codepen https://codepen.io/jfirestorm44/pen/RwKdpRw
BA • BC is a "dot product" between two vectors. The result is a single number: It's the sum of the products of vector components. If the vectors are (x1,y1) and (x2,y2) the dot product is x1x2+y1y2.
Assuming you don't have a library for vector calculations and don't want to create one, the code for computing k would be:
k = (-xb*(xc - xb)-yb*(yc - yb)) / ac

JS | How to lerp rotation in radians?

function lerp(start, end, amt) {
return (1-amt)*start+amt*end
}
This lerp function works perfectly with coords. I can easily lerp X from 1 to 10.
But problems appear when it comes to rotation. The rotation of an object is in radians. It can be from -3.14 to 3.14. So let's rotate our object. Starting from 0, one moment the rotation will reach to 3.14, and then... -3.14. So when lerping from 3.14 to -3.14, the object makes one full 360º rotation, (3.14, 2, 1, 0, -1, -2, -3.14) which is not good. So, can anybody tell, how to lerp the rotation?
I am using JavaScript.
Honestly, I don't remember how this works. But, it works.
Its in my code to deal with lerping rotation of a player object to point towards the mouse, when the pointer angle traverses -3.14 to 3.14 this function correctly calculates the lerp across the gap. With, um, magic.
function rLerp (A, B, w){
let CS = (1-w)*Math.cos(A) + w*Math.cos(B);
let SN = (1-w)*Math.sin(A) + w*Math.sin(B);
return Math.atan2(SN,CS);
}
If end value is less than start one, increment it by 2*Pi, and make interpolation.
Map intermediate values into needed range.
Python code (JS one is close)
a0 = 3
a1 = - 3
if a1 < a0:
a1 += 2*math.pi
for i in range(11):
a = a0 * (1 - i/10) + a1 * i / 10
if a > math.pi:
a -= 2*math.pi
print(a)
3.0
3.028318530717959
3.0566370614359175
3.0849555921538756
3.113274122871834
3.141592653589793
-3.113274122871834
-3.084955592153876
-3.056637061435917
-3.028318530717959
-3.0

How to calculate the angle to shoot a bullet in order to hit a moving target?

I found one interesting project on that is requiring to calculate the angle to shoot a bullet in order to hit a moving object/target. There are five parameters that should be provided in this function. Here is the list of the arguments:
`xP` - last known x position of the target
`yP` - last known y position of the target
`xV` - last known x velocity of the target
`yV` - last known y velocity of the target
`bulletS` - the speed of the bullet
For example if I provide set of parameters like this:
xP yP xV yV bulletS
5 5 0 1 3
4 4 1 0 2
5 5 0 -1 3
So far I was able to calculate the distance but I'm not sure if that is correct. Here is example:
import java.lang.*;
public class Problem2 {
public static void main(String[] args) {
// Function takes arguments from the parameters table.
System.out.println(calculateShotAngle(10,10,1,0,2));
}
static double calculateShotAngle(float xP, float yP, float xV, float yV, float pSpeed) {
// Function equation to calculate distance
double distance = Math.pow(Math.sqrt(Math.pow((xV-xP),2) + Math.pow((yV-yP), 2)),2);
return distance;
}
}
Once I get the distance I should use speed of the bullet to get an angle. I'm trying to understand how this algorithm should work. I guess the distance between the target and the bullet should be calculated first then check if bullet reached the target. If anyone have an example or tips how this should be achieved please let me know. Thank you.
This problem is complicated but I will try to make a descriptive answer.
We need to establish some constants, like gravity (for now only gravity):
double gravity = 0.98;
// Add more constants if needed
After establishing the need constants we will do the calculations.
=========== PART 1 ===========
First you need to know where your target is moving by using the Projectile Motion Formula.
Here are the need variables for the target:
`xPT` - last known x position of the target
`yPT` - last known y position of the target
`xVT` - last known x velocity of the target
`yVT` - last known y velocity of the target
After that calculate the position of the target at time t.
Where:
Vx is the velocity along x-axis (You need to calculate this)
Vxo is the initial velocity along x-axis (the xVT)
Vy is the velocity along y-axis (You need to calculate this)
Vyo is the initial velocity along y-axis (the yVT)
g is the acceleration due to gravity
t is the time taken
Just start t at 1 then increment it. (Play with the initial value and increment to get the desired output)
=========== PART 2 ===========
After calculating the location of the target at time t, you then calculate the possible launch angle of the bullet given the position and speed if it can reach the position of the target at time t, if it can reach then the angle will be the answer, if not increment t
The needed variables for the bullet are:
`xPB` - last known x position of the bullet
`yPB` - last known y position of the bullet
`bulletS` - the speed of the bullet
The formula to calculate the angle is:
Where :
v is initial launch speed (this is bulletS)
g is the gravity constant
x is the x position of the target at time t (this is xPT)
y is the y position of the target at time t (this is yPT)
=========== PART 3 ===========
Using the angle, speed, initial position of the bullet check if the bullet can reach the target's position at time t
The formula is:
Where :
u is initial launch speed (this is bulletS)
g is the gravity constant
θ is the launch angle
Ux is initial x velocity of the bullet
Uy is initial y velocity of the bullet
After that calculate the position of the bullet at time t.
Where:
x is the x position of the bullet at time t
y is the y position of the bullet at time t
Vx is the velocity along x-axis (You need to calculate this)
Vxo is the initial velocity along x-axis (the Ux)
Vy is the velocity along y-axis (You need to calculate this)
Vyo is the initial velocity along y-axis (the Uy)
g is the acceleration due to gravity
t is the time taken
xPB - last known x position of the bullet
yPB - last known y position of the bullet
=========== PART 4 ===========
Now you have the need variables, which are:
`xPB` - last known x position of the bullet
`yPB` - last known y position of the bullet
`xPT` - last known x position of the target
`yPT` - last known y position of the target
Compare the above variables, if xPB is equal to xPT and yPB is equal to yPT then the bullet will hit the target at time t and at launch angle θ. If not then increment time t and do Part 1 until Part 4.
=========== SUMMARY ===========
This will be the flow of your program.
static double calculateShotAngle(
double xPT, double yPT, double xVT, double yVT,
double xPB, double yPB, double bulletS) {
double gravity = 0.98;
double angle = null;
double time = 1; // change this value if needed (try smaller increments if after a single increment the bullet's position will pass the target's position)
double xPTOriginal = xPt; // Save the initial x position of target
double yPTOriginal = yPt; // Save the initial y position of target
while (true) {
// do Part 1;
// do Part 2;
// do Part 3;
// below code is Part 4
if (hasBeenHit(xPT, yPT, xPB, yPB)) {
break;
} else {
t++; // increment t
// Revert the initial position of target
xPt = xPTOriginal;
yPt = yPTOriginal;
}
}
return angle;
}
// Method used to check if bullet hits the target
// Method assumes that bullet and target only occupies a point (1 of axis x and 1 of axis y)
static boolean hasBeenHit(double xPT, double yPT, double xPB, double yPB) {
return xPT == xPB && yPT == yPB;
}
I hope you understand my explanation (I've spent a lot of time making it. Haha) But if you have any questions/clarifications, feel free to comment it.
Assuming the bullet will be fired from origin (0,0).
If the bullet meets the target after time t, then equation would be:
(xP + xV * t, yP + yV * t) = ((bullets * t) * cos(angle), (bullets * t) * sin(angle))
Now, If you solve it, you will get
xP = (bullets * cos(angle) - xV) * t /* equation 1 */
yP = (bullets * sin(angle) - yV) * t /* equation 2 */
Dividing equation 1 with equation 2 you get:
xP * sin(angle) - yP * sin(angle) = (xP * yV - xV * yP) / bullets
Now, if you assume m = sin(angle), then cos(angle) = sqrt(1 - m * m)
So now, you have to solve the equation:
xP * m - yP * sqrt(1 - m * m) = (xP * yV - xV * yP) / bullets
Move the term with square root on one side and the rest on other, so that you get a quadratic equation after squaring and you can solve that equation to get 2 valuee in terms of m = sin(angle)
So, the final angle is angle = arcsin(m)

How can I make a tetradecagon with Processing.Js?

I want to make a Tetradecagon, a polygon with 14 sides, with Processing.JS.
(I want to make the Tetradecagon like the one shown in the Image below!)
Using the numbers given in the image, which I would like to replicate, I concluded that each piece (I don't know it's proper name), has an angle of 25.714285714°.....25 and 10/14 = 25 and 5/7 - 5/7 in decimal form = 0.714285714So, I arrived at 25.714285714°
Now, in Processing.JS, I was wanting to use a while loop:
var r = 0;
var draw = function() {
translate(200,200);
while(r < 361){
rotate(r);
r = r + 25.714285714;
line(200,0,200,200);
}
};
Here, I have set one variable, r. r will be the variable for the rotate() function. The while loop will keep going until r meets 360 - this will allow for the the change in r, the angle, to increase by 25.714285714°, while r < 361.
But, sadly, this is not happening. What I see on my canvas is the line being shot off the screen.
(edit) I added translate(200,200); just above the while() loop - this helped, but the lines are still not looking like the picture above.
The second point of the line is not staying in the center; the whole line is being shifted. I only want the first (top) point to be shifted by the given change in angles.
How do I change the code in order to achieve the goal that I am striving for? Any help would be appreciated - Thanks for your time!
P.S. This is my result with the current code -
Processing.js is just for running Processing code. This looks like a mix of Processing and Javascript code so my first advice would be "write real Processing code".
With that said, if you want to do this based on coordinate rotation, look at your 14-gon: it's 14 repeated triangles, so analyze one triangle and draw that 14 times. Any triangular slice is defined by a line from "the center" to "a vertex on the 14-gon" at a (necessary) distance r, the radius of the circumscribing circle. So, given a vertex (r,0) on the 14-gon where is the next vertex (nx,ny)?
Simple maths:
first vertex = (x, y) = (r,0)
next vertex = (nx,ny) = (r,0) rotated over (0,0) by (phi = tau/14)
(I'm using tau here because it's a far more convenient constant for programming purposes. It's simply equal to 2*pi, and as such represents an entire circle, rather than a half circle)
Now, computing that rotate coordinate using basic trigonometry:
nx = r * cos(phi) - 0 * sin(phi) = r * cos(phi)
ny = r * sin(phi) + 0 * cos(phi) = r * sin(phi)
Alright, done. And this nx,ny computation is clearly not specific to the number 14, it about arbitrary angles, so let's code the solution and make it work for any n-sided polygon:
void setup() {
size(400,400);
noLoop();
}
void draw() {
background(255);
// offset the coordinate system so that (0,0) is the sketch center
translate(width/2,height/2);
// then draw a polygon. In this case, radius width/2, and 14 sided
drawNgon(width/2, 14);
}
void drawNgon(float r, float n) {
// to draw (r,0)-(x',y') we need x' and y':
float phi = TAU/n;
float nx = r * cos(phi);
float ny = r * sin(phi);
// and then we just draw that line as many times as there are sides
for(int a=0; a<n; a++) {
// draw line...
line(r,0, nx,ny);
// rotate the entire coordinate system...
rotate(phi);
// repeat until done.
}
}
And now we can freely change both the polygon radius and the number of sides by changing the input to drawNgon(..., ...).

Algorithm for random land in a "Tank Wars" game [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Did you ever played the "Tank wars" game?
I'm programming this game with JavaScript + Canvas (for a personal challenge), and what I need is an algorithm for generating that random green land every time I start the game, but I'm not too good at maths, so I can't do it myself.
I don't want someone to give me the code, I only want the idea for the algorithm.
Thanks!
(9 segments)
Fiddle demo
(7 segments)
The main generation function look like this:
var numOfSegments = 9; // split horizontal space
var segment = canvas.width / numOfSegments; // calc width of each segment
var points = [], calcedPoints;
var variations = 0.22; // adjust this: lower = less variations
var i;
//produce some random heights across the canvas
for(i=0; i < numOfSegments + 1; i++) {
points.push(segment * i);
points.push(canvas.height / 2.8 + canvas.height * variations * Math.random());
}
//render the landscape
ctx.beginPath();
ctx.moveTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
calcedPoints = ctx.curve(points); // see below
ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();
The curve() function is a separate function which generate a cardinal spline. In here you can modify it to also store tension values to make more spikes. You can also used the generated points as a basis for where and at what angle the tanks will move at.
The function for cardinal spline:
CanvasRenderingContext2D.prototype.curve = function(pts, tension, numOfSegments) {
tension = (tension != 'undefined') ? tension : 0.5;
numOfSegments = numOfSegments ? numOfSegments : 16;
var _pts = [], res = [], t, i, l, r = 0,
x, y, t1x, t2x, t1y, t2y,
c1, c2, c3, c4, st, st2, st3, st23, st32;
_pts = pts.concat();
_pts.unshift(pts[1]);
_pts.unshift(pts[0]);
_pts.push(pts[pts.length - 2]);
_pts.push(pts[pts.length - 1]);
l = (_pts.length - 4);
for (i = 2; i < l; i+=2) {
//overrides and modifies tension for each segment.
tension = 1 * Math.random() - 0.3;
for (t = 0; t <= numOfSegments; t++) {
t1x = (_pts[i+2] - _pts[i-2]) * tension;
t2x = (_pts[i+4] - _pts[i]) * tension;
t1y = (_pts[i+3] - _pts[i-1]) * tension;
t2y = (_pts[i+5] - _pts[i+1]) * tension;
st = t / numOfSegments;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;
c1 = st23 - st32 + 1;
c2 = -(st23) + st32;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;
x = c1 * _pts[i] + c2 * _pts[i+2] + c3 * t1x + c4 * t2x;
y = c1 * _pts[i+1] + c2 * _pts[i+3] + c3 * t1y + c4 * t2y;
res[r++] = x;
res[r++] = y;
} //for t
} //for i
l = res.length;
for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]);
return res; //return calculated points
}
Look into perlin noise generation, this in combination with a good smoothing algorithm can produce some pretty good terrain, and is fairly quick. There is a reference version of the code kicking around the net somewhere, which should provide you with a fairly hefty headstart
First you need a point that is random y (between 55,65); got x=0
So this is the origin point for the green, lets keep it as x1,y1 (x1 always 0).
Then you need a random integer between 30 to 40. This is x2. And a random y which is in the range y1 + 8 to y1 + 20.
Then x3 and y3 on same principle (lets call it formula type 1)
Now you need to first get a random either -1 or 1, this will be directions of y4. So y4 can go higher than y3 or lower ... this will be formula type 2.
You need to keep a max and min y for a new y, if it crosses that then go the other way -> this will be a correction type formula 3.
Xn keeps increasing till its >= width of board.
Join the lines in a eclipses ... and looks like web searches is the way to go !
I am sure there are a lot of coded libraries that you could use to make this easy. But if you are trying to code this by yourself, here is my idea.
You need to define terrain from everything else. So every part of your environment is a cluster for example. You need to define how are separated these clusters, by nodes(points) for example.
You can create a polygon from a sequence of points, and this polygon can become whatever you want, in this case terrain.
See that on the image you passed, there are peaks, those are the nodes (points). Remember to define also nodes on the borders of your environment.
There are surely a novel, written algorithms, either fractal as #DesertIvy pointed out or others, maybe there are libraries as well, but if you want toi generate what is in the image, it can be pretty straightforward, since it is just (slightly curved) lines between points. If you do it in phases, not trying to be correct at once, it is easy:
Split x region of your game screen into sections (with some minimal and maximal width) using random (you may be slightly off in last section, but it does not matter as much, I think). Remember the x-es where sections meet (including the ones at game screen border)
Prepare some data structure to include y-s as well, on previously remembered x-s. Start with leftmost.y = 0, slope = Math.random()-0.5;.
Generate each next undefined y beginning with 1: right.y = left.y + slope * (right.x-left.x); as well as update slope after each y: slope += Math.random()-0.5;. Do not bother, for the moment, if it all fits into game screen.
If you want arcs, you can generate "curviness" parameter for each section randomly which represent how much the middle of the line is bumped compared to straight lines.
Fit the ys into the game screen: first find maximal and minimal generated y (mingeny, maxgeny) (you can track this while generating in point 4). Choose where the max and min y in game screen (minscry, maxscry) (say at the top fourth and at the bottom fourth). Then transform generated ys so that it spans between minscry and maxscry: for every point, do apoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny).
Now use lines between [x,y] points as a terrain, if you want to use "curviness", than add curvemodifier to y for any particular x in a section between leftx and rightx. The arc need not to be a circle: I would suggest a parabola or cosine which are easy to produce: var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left); and then either var curvemodifier = curviness * (1-excess*excess); or var curvemodifier = curviness * Math.cos(Math.PI/2*excess).
Wow...At one point I was totally addicted to tank wars.
Since you are on a learning adventure...
You might also learn about the context.globalCompositeOperation.
This canvas operation will let you grab an image of actual grass and composite it into your game.
You can randomize the grass appearance by changing the x/y of your drawImage();
Yes, the actual grass would probably be too distracting to include in your finished game, but learning about compositing would be valuable knowledge to have.
...and +1 for the question: Good for you in challenging yourself !

Categories