I am making a simple animation for fun with a bit of a festive theme. The component I am working on right now is some snowflakes falling. I am keeping things simple; several layers of snowfall each on a separate canvas which move downwards at some rate, each canvas wraps back to the top to make a never-ending fall of snow with parallax.
Currently the position of each snowflake is random (using Math.random()), but the effect is a bit lack lustre, far too even. What I want is snow function that produces a better looking distribution.
The pseudo-code for positioning the flakes looks something like this:
for (var i = 0; i < 1000; i++) {
var coords = placeFlake();
// Take the generated co-ords and place a snowflake on the canvas.
}
function placeFlake() {
// Just return an array of random co-ords within width and height.
var x = // random number within the width
var y = // random number within the height
return [x,y];
}
Just wondered if anybody had any ideas for a replacement for placeFlake()?
Related
I'm looking to have an algorithm that can randomly draw a "squiggly wiggly" pattern as per the picture.
It would be nice if it were progressively drawn as you would draw it with a pen and if it were based on speed, acceleration and forces like a double pendulum animation might be.
This would be for javascript in the p5 library.
Is there some way of producing this that a) looks hand drawn and b) fills a page, somewhat like a Hilbert curve?
Very interested to hear ideas of how this could be produced, regardless of whether there is some kind of formal algorithm, although a formal algorithm would be best.
Cheers
I can think of two solutions, but there could be more as I'm not very good at coding in general yet.
First of all, you can use perlin noise. With the code
var noiseSeeds = [];
//This changes the noise value over time
var noiseTime = 0;
var x = 0;
var y = 0;
function setup() {
createCanvas(400, 400);
//This will help for making two separate noise values later
noiseSeeds = [random(100), random(100)];
}
function draw() {
//Finding the x value
noiseSeed(noiseSeeds[0]);
x = noise(noiseTime)*400;
//Finding the y value
noiseSeed(noiseSeeds[1]);
y = noise(noiseTime)*400;
//Increasing the noise Time so the next value is slightly different
noiseTime += 0.01;
//Draw the point
stroke(0);
strokeWeight(10);
point(x, y);
}
You can create a scribble on screen. You would have to use createGraphics()in some way to make this more efficient. This method isn't the best because the values are generally closer to the center.
The second solution is to make a point that has two states - far away from an edge and close to an edge. While it is far away, the point would keep going in relatively the same direction with small velocity changes. However, the closer the point gets to the edges, the (exponentially) bigger the velocity changes so that the point curves away from the edge. I don't know exactly how you could implement this, but it could work.
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 have a total of 1 to 64 blobs and they all move to my mouse position. But i want them to not go into each other, in other words circle collision detection. However i can't seem to make it smooth and also push new objects after they move for the first time?
Tried checking each blob for collision with other blobs. If collosion is true, then set the distance between the blobs to their accumulated radiuses.
This is how i wrote the colliding function, but this way of doing it makes the resetting of positions too fast. I want it to be a smooth, but fast transition. Like instead of now 1 frame, lets say 10 frames. And another problem is when two objects' are distanced to their radiuses, they might collide into new ones and that will cause this code to run again, and then all blobs go crazy.
this.collide = function() {
var length = this.blobs.length; // How many blobs?
this.blobs.forEach(function(item, index) {
for (var i = 0; i < length; i++) {
// Get absolute distance between two vectors
var v0 = vectorFromTo(blob.blobs[i].pos.x, blob.blobs[i].pos.y, //[x2, y2]
item.pos.x, item.pos.y); //[x1, y1]
// if colliding, set distance between to their accumulated radiuses
if (magnitude(v0) < blob.blobs[i].r + item.r) {
item.pos.add(v0.setMag(magnitude(v0) - (blob.blobs[i].r + item.r)));
}
}
});
}
I haven't tried to code another way of doing this yet because i haven't learned about vectors in school, but i do understand them quite a bit. But what i think would work is if i checked for collision, and if they collide they go opposite directions 50% of the deficit distance, and then they check if they hit new blobs. But this would require physics right? Cause then it would have to do something with the mass and speed of the blob as well to know whats gonna happen to the new blob it crashes into?
EDIT:
This is what im looking for: https://youtu.be/QvlhRGtlcsw
This is what it currently looks like: https://youtu.be/QEpHnCgomqY
Im working on a little project, I have some particles i want to move towards target positions without exceeding a max velocity, first i tried capping the X and Y velocities seperately which caused the hypotenuse of the two to be able to go over the max speed, i then remembered my maths classes and attempted this:
var totalVel = Math.sqrt(Math.pow(curVelocity[0],2) + Math.pow(curVelocity[1],2));
if(totalVel > maxSpeed){
//sin(θ) = Opposite / Hypotenuse
var angle = Math.asin(curVelocity[1]/totalVel);
var newHyp = maxSpeed;
var newOp = Math.sin(angle)*newHyp;
var newAdj = Math.sqrt(Math.pow(newHyp,2) - Math.pow(newOp,2));
curVelocity[1] = newOp;
curVelocity[0] = newAdj;
}
(curVelocity is an array where index 0 is X and index 1 is Y)
This works well hald the time, the other time it curves away from the target its trying to reach.. matches it on the Y plane but heads in the whole wrong direction in the X plane. im guessing its something to do with using math.sin when perhaps it no longer applies in the direction its traveling but i wouldnt know where ot begin differentiating what to use, or if that idea is even correct.
A live example of what im talking about can be found at this location here, refreshing the page will change the starting location and target location, the black circle is the particle the green circle is the target location
I've got an ipad webapp I'm working on where you can draw on a canvas and save it. Like a more basic paint program. I need to be able to upload and image to the background and draw on it. Right now that wouldn't be too difficult since I got the drawing functionality and it wouldn't be hard to just print the image to the background and draw on it. The problem I'm having is that it also needs to have manageable layers. This means it needs to support alpha pixels.
So what I've done is written a panel class that when paint is called it moves down through it's child panels and paints their buffered images to the temp image. Then I take that and paint it over the parent- continueing until the image is flattened to a temporary image.
This works fine- especially on a desktop. But to accomplish this I had to write the putImageData code from scratch which loops through the array of pixels and paints them taking the alpha in account. Like so-
var offset = (canvasW*4*y)+x*4;
for(var r = 0; r < newHeight; r++)
{
var lineOffset = (size.width*4 - columns)*r + offset;
for(var c = 0; c < columns; c+=4)
{
var start = (r*columns)+c;
var destStart = start+lineOffset;
var red = imageData[start];
var green = imageData[start+1];
var blue = imageData[start+2];
var alpha = imageData[start+3];
var destRed = canvasData[destStart];
var destGreen = canvasData[destStart+1];
var destBlue = canvasData[destStart+2];
var destAlpha = canvasData[destStart+3];
var opacity = alpha/255;
var destOpacity = destAlpha/255;
var invOpacity = 1-opacity;
var newRed = Math.abs(red - ((red-destRed)*invOpacity));
var newGreen = Math.abs(green - ((green-destGreen)*invOpacity));
var newBlue = Math.abs(blue - ((blue-destBlue)*invOpacity));
canvasData[start+lineOffset] = newRed;
canvasData[start+lineOffset+1] = newGreen;
canvasData[start+lineOffset+2] = newBlue;
canvasData[start+lineOffset+3] = 255;
}
}
This takes about 50 miliseconds per layer. Not very good for a desktop. Takes a whopping 1200 miliseconds for the ipad! So I tested it with the original putImageData (which doesn't support alpha) and it was still not very impressive but it's the best I got I'm thinking.
So here is my problem. I know there is an overal opacity for drawing with canvases but it needs to be able to draw some pixels completely opaque and some completely transparent. Is there an putImageData that includes opacity?
If not any recommendations on how I can accomplish this?
As #Jeffrey Sweeney mentioned, try stacking canvases on top of each other. For one of my Javascript library, CInk (search there for z-index), I did the same thing.
I had one container div, which I stuffed with many canvas DOMs to mimic the layers. All canvas DOMs are absolutely positioned and their z-index define the order of the layers. In your case you will have to apply style at specific layers to set its opacity.