How to simulate mouse movement to procedurally generate beautiful galaxies in JS? - javascript

I'm working on a project that procedurally generates images of galaxies like this one:
This sample was "hand drawn" (by waving the cursor around). See this pen:
https://codepen.io/OpherV/pen/JQBKVq?editors=0110
I would like to procedurally generate these types of images, but rather than generate them at one go I'd like the generation be performed using a "drawing" process, that is, moving the drawing cursor in a pattern that achieves these visual structures.
The mouse-simulation code that I currently have is lifted directly from Louis Hoebregts' "Simulating Mouse Movement" article on CSS Tricks.
The principle function relies on Simplex noise:
const s = 0.001 * (speed / 100);
const noiseX = (noise.simplex3(1, 0, a * s) + 1) / 2;
const noiseY = (noise.simplex3(11, 0, a * s) + 1) / 2;
random += randomness / 1000;
const randX = noise.simplex3(1, 0, random) * window.innerWidth * 0.1;
const randY = noise.simplex3(3, 0, random) * window.innerHeight * 0.1;
const x = noiseX * innerWidth + randX;
const y = noiseY * innerHeight + randY;
updateMouse(x, y);
However this type of noise won't create the visuals I'm aiming for. Breaking down the visual structure I have in mind, we have a center-weighted blob and elliptical "arms". To achieve the former, I think more "drawing time" should be performed near the center (which creates the bright blobs inside), with less often "offshoots" performing more elliptic motion to make the latter.
I thought about somehow gradienting the Simplex noise so that it veers more towards the center, but I'm unsure how to go about doing that in 2d space. I'm also not certain how to proceed combining that with something that draws the "arms" of the galaxy.
Can you suggest an algorithm to achieve this?
Thanks 🙏

If you only want to generate images, you could look into generating a galaxy with some number of spiral arms using cos and sin, play around with the circle radius:
Math.cos(radians) * radius, Math.sin(radians) * radius
Get this to work first.
You probably want to draw something somewhat elliptical instead of a full circle.
Randomly go more often in the center of the galaxy and close to the arms.
Step 1: Randomly generate galaxy points
Step 2: Blend colors (HTML5 canvas paint blending color tool)
Step 3: if you want realtime performance use WebGL ...
Bonus: if you want to go full overkill you could even try to use realistic formulas:
https://arxiv.org/pdf/0908.0892.pdf

Related

Find relative angle between two points

I am designing a web script to automatically create a Java file to perform autonomous actions for a robotics team based on nodes created by the player. It also features a simulation to check collision (I could use an algorithm to do this but sometimes we want it to hit the walls). The robot takes relative degrees, but atan2 gives radians on the unit circle. If I use atan, it just doesn't work right. I've tried this:
function findDegrees(node1, node2){
return Math.atan((node2.y - node1.y) / (node2.x - node1.x)) * 180 / Math.PI;
}
But it just doesn't work. This piece of code writes the data too the output. (Also, I'm following the pattern: Drive, then turn towards next node).
let theta = currentAngle - findDegrees(nextNode, twoNodes);
currentAngle += theta;
if (theta && typeof theta !== 'undefined'){
middle += `${INDENTSPACE}turn(${theta}, 1.0);\n`;
}
The way I change the x and y of the robot simulation is this:
turn(degrees, speed){
this.theta -= degrees;
}
But sometimes it goes the other way. How do I get the robot to rotate at a relative angle to the current angle where directly forward is 0°? (If you want the full code here it is.)

detect collision between two circles and sliding them on each other

I'm trying to detect collision between two circles like this:
var circle1 = {radius: 20, x: 5, y: 5}; //moving
var circle2 = {radius: 12, x: 10, y: 5}; //not moving
var dx = circle1.x - circle2.x;
var dy = circle1.y - circle2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < circle1.radius + circle2.radius) {
// collision detected
}else{
circle1.x += 1 * Math.cos(circle1.angle);
circle1.y += 1 * Math.sin(circle1.angle);
}
Now when collision is detected I want to slide the circle1 from on the circle2 (circle1 is moving) like this:
--circle1---------------------------------circle2-------------------------
I could do this by updating the angle of circle1 and Moving it toward the new angle when collision is detected.
Now My question is that how can I detect whether to update/increase the angle or update/decrease the angle based on which part of circle2 circle1 is colliding with ?? (circle one comes from all angles)
I would appreciate any help
This will depend a bit on how you are using these circles, and how many will ever exist in a single system, but if you are trying to simulate the effect of two bodies colliding under gravity where one roles around to the edge then falls off (or similar under-thrust scenario), then you should apply a constant acceleration or velocity to the moving object and after you compute it's movement phase, you do a displacement phase where you take the angle to the object you are colliding with and move it back far enough in that direction to reach circle1.radius + circle2.radius.
[edit] To get that redirection after falling though (not sure if you intended this or if it's just your sketch), there is probably going to be another force at play. Most likely it will involve a "stickiness" applied between the bodies. Basically, on a collision, you need to make sure that on the next movement cycle, you apply Normal Movement, then movement towards the other body, then the repulsion to make sure they don't overlap. This way it will stick to the big circle until gravity pulls way at enough of a direct angle to break the connection.
[edit2] If you want to make this smoother and achieve a natural curve as you fall away you can use an acceleration under friction formula. So, instead of this:
circle1.x += 1 * Math.cos(circle1.angle);
circle1.y += 1 * Math.sin(circle1.angle);
You want to create velocity properties for your object that are acted on by acceleration and friction until they balance out to a fixed terminal velocity. Think:
// constants - adjust these to get the speed and smoothness you desire
var accelerationX = 1;
var accelerationY = 0;
var friction = 0.8;
// part of physics loop
circle1.velX += (accelerationX * Math.cos(circle1.angle)) - (friction * circle1.velX);
circle1.velY += (accelerationY * Math.sin(circle1.angle)) - (friction * circle1.velX);
circle1.x += circle1.velX;
circle1.y += circle1.velY;
This way, when things hit they will slow down (or stop), then speed back up when they start moving again. The acceleration as it gets back up to speed will achieve a more natural arc as it falls away.
You could get the tangent of the point of contact between both circles, which would indicate you how much to change your angle compared to the destination point (or any horizontal plane).

N-Body Gravity / Solar System Javascript Simulation

Good day, I am trying to create a simple 2D solar system model in javascript, but am having some trouble understanding how to go about calculating where planets will be for the next frame, aswell as a few other bits which I'll go into detail with soon.
After watching this very nice video and a whole bunch of his others, I made a quick MS paint image to try and simplify my situation.
With the second scene, you can see that the new position is calulated using the velocity, gravitational pull, and the angle between these two 'directions'?
I cannot get my head around how to figure this all out.
Below is a JS fiddle of my code. You'll notice I'm trying my best to use real NASA given data to keep it accurate.
You'll want to look specifically at lines 138 which is where all the calculations for its next move are made.
https://jsfiddle.net/c8eru7mk/9/
attraction: function(p2) {
// Distance to other body
var dx = p2.position.x - this.position.x;
var dy = p2.position.y - this.position.y;
var d = Math.sqrt(dx ** 2 + dy ** 2); // Possibly correct
// Force of attracrtion
this.f = G * (this.mass * p2.mass) / (d ** 2); // Possibly Correct
// Direction of force, If you read it hard enough you should be able to hear my screams of pain
// Not sure if this is correct, most likely not.
var theta = Math.atan2(dy, dx);
var fx = Math.cos(theta) * this.f;
var fy = Math.sin(theta) * this.f;
this.velocity.x += fx / this.mass;
this.velocity.y += fy / this.mass;
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
}
The problems I'm currently facing are
If I am to use NASA values, the distance between planets is so big, they won't fit on the screen, and I can't simply scale the distances down by multiplying them by 0.0002 or whatever, as that'll mess with the gravitational constant, and the simulation will be completely off.
I have no idea how to caluclate the next position and my brain has imploded several times this past week trying to attempt it several times.
I have no idea on how to check if my configuration data of planets is wrong, or if the simulation is wrong, so I'm pretty much just guessing.
This is also my first time actually coding anything more complex than a button in javascript too, so feedback on code layout and whatnot is welcome!
Many thanks
Using NASA values is not a problem when using separate coordinates for drawing. Using an appropriate linear transfomration from real coordinates to screen coordinatees for displaying does not influence the physical values and computations.
For simulating the motion of a planet with iterative updates one can assume that the gravitational force and the velocity are constant for a small portion of time dt. This factor dt is missing in your conversions from accelration to velocity and from velocity to distance. Choosing an appropriate value for dt may need some experiments. If the value is too big the approximation will be too far off from reality. If the value is too small you may not see any movement or rounding errors may influence the result.
For the beginning let us assume that the sun is always at (0,0). Also for a start let us ignore the forces between the planets. Then here are the necessary formulas for a first not too bad approximation:
scalar acceleration of a planet at position (x,y) by the gravitational force of the sun (with mass M): a = G*M/(d*d) where d=sqrt(x*x+y*y). Note that this is indepent of the planet's mass.
acceleration vector: ax = -a*x/d, ay = -a*y/d (the vector (-x,-y) is pointing towards the sun and must be brought the length a)
change of the planet's velocity (vx,vy): vx += ax*dt, vy += ay*dt
change of the planet's position: x += vx*dt, y += vy*dt

How to implement a repulsion between 2D circles (paperjs)

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)

Algorithm for moving an object horizontally in javascript

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?)

Categories

Resources