Algorithm for drawing a "Squiggly wiggly" pattern - javascript

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.

Related

struggling to create a smooth-moving snake in p5 js - tail catching up to head

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.

How to make multiple circle objects not go into each other with collision detection?

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

Image Flickering In Canvas Game

For a university project I have been tasked with creating a Flappy Bird clone. It's being done using the HTML5 canvas.
The issue doesn't happen very often, but it seems that every 6 or so seconds, the grass will flicker. I'm not sure what's causing this, it could be a performance issue.
Here is a link so you may see the issue: http://canvas.pixcelstudios.uk
Here is the function I'm using to the draw the grass:
var drawGrass = function(cWidth, ctx, minusX)
{
var x = bg_grass.x;
var y = bg_grass.y;
var w = bg_grass.w;
var h = bg_grass.h;
var img = bg_grass.img;
if (minusX[0] >= cWidth)
{
bg_grass.x = 0;
minusX[0] = 0;
}
ctx.drawImage(img, x, y, w, h);
if (minusX[0] > 0)
{
ctx.drawImage(img, w-minusX[0], y, w, h);
}
};
Basically, I'm drawing two grass sprites, each taking up a canvas width. One starts with an X of 0 and the other starts at the end of the canvas. Both are decremented each frame, then one is completely off the screen, it's completely reset to keep it looping.
I don't think it's anything to do with my update loop which is as follows:
this.update = function()
{
clearScreen();
updateBackground();
updatePositions();
checkCollisions();
render();
requestAnimFrame(gameSpace.update);
};
I've done a little bit of reading and I've read about having a second canvas to act as a buffer. Apparently this can stop flickering and improve performance? But all of the examples I've seen show the parts being drawn into the canvas out of a loop and I can't really see how doing it within a game loop (moving parts and all) would increase performance rather than decrease it. Surely the same operations are being performed, except now you also have to draw the second canvas onto the first?
Please let me know if you need any more information (although you should be able to see the whole source from the web link).
Thanks!
Okay I found the issue! Was just a simple mistake in my drawGrass function.
Due to the ordering, there'd be just a single frame where I'd set my shorthand X variable to bg_grass.x and THEN set bg_grass.x to something else, therefore drawing the wrong value.
I've now set my shorthand variables after the first if-statement.
However, if anyone could provide any insight into the second part of the question regarding a buffer canvas, I'd still much appreciate that.

Canvas: curve failing to start from end point of previous curve

I'm using the algorithm posted by the author of the question in the below thread to draw an N point bezier curve defined by some array of points.
how to draw smooth curve through N points using javascript HTML5 canvas?
Here's a fiddle of the project:
http://jsfiddle.net/lee2808/2YVx4/
If you copy and paste that into a js file and replace "AddImage.png" in the Curve's Ctor call on line 15 with an image file, all should work fine! You need to click on the canvas three times for the curve to begin to draw.
I'm dynamically adding points on a mousedown + mouseup event.
Anyway my implementation half works (if that's a thing lol). Once I have placed the first 3 points on the canvas a bezier is drawn as expected. However when I add further points the start point for the next curve is not at the end point of the previous curve.
It seems it's starting from the previous point.
Anyway here's my implementation :
Curve.prototype.drawCurve = function(pContext){
pContext.save();
if(this.getPoints().length >2){
pContext.moveTo(this.getPoints()[0].getX(),this.getPoints()[0].getY());
var i = 1;
for(i; i < this.getPoints().length-2; i++){
var modX = (this.getPoints()[i].getX() + this.getPoints()[i+1].getX()) /2;
var modY = (this.getPoints()[i].getY() + this.getPoints()[i+1].getY()) /2;
pContext.quadraticCurveTo(this.getPoints()[i].getX(), this.getPoints()[i].getY(),modX,modY);
}
if(this.getPoints().length > 2){
pContext.quadraticCurveTo(this.getPoints()[i].getX(),this.getPoints()[i].getY(), //last control point
this.getPoints()[i+1].getX(),this.getPoints()[i+1].getY());//end point
}
pContext.stroke();
}
pContext.restore();
};
Pretty much identical. Can anyone see the flaw in my logic?
I'm trying to produce a chain of bezier curves so that I can then animate an object to follow that path incase anyones interested as to why I want to do this.
Thanks in advance!

Javascript physics engine and simulated infinite curve

I'm trying to do a Tiny Wings like in javascript.
I first saw a technique using Box2D, I'm using the closure-web version (because of the memory leaks fix).
In short, I explode the curve into polygons so it looks like that:
I also tried with Chipmunk-js and I use the segment shape to simulate my ground like that:
In both cases, I'm experiencing some "crashes" or "bumps" at the common points between polygons or segments when a circle is rolling.
I asked about it for Chipmunk and the author said he implemented a radius property for the segment to reduce this behavior. I tried and it indeed did the trick but it's not perfect. I still have some bumps(I had to set to 30px of radius to get a positive effect).
The "bumps" append at the shared points between two polygons :
Using, as illandril suggested to me, the edging technique (he only tested with polygon-polygon contact) to avoid the circle to crash on an edge:
Also tried to add the bullet option as Luc suggested and nothing seems to change.
Here the demo of the issue.
You can try to change the value to check :
bullet option
edge size
iterations count
the physics
(only tested on latest dev Chrome)
Be patient (or change the horizontal gravity) and you'll see what I mean.
Here the repo for the interested.
The best solution is edge shapes with ghost vertices, but if that's not available in the version/port you're using, the next best thing is like the diagram in your question called 'edging', but extend the polygons further underground with a very shallow slope, like in this thread: http://www.box2d.org/forum/viewtopic.php?f=8&t=7917
I first thought the problem could come from the change of slope between two adjacent segments, but since on a flat surface of polygons you still have bumps I think the problem is rather hitting the corner of a polygon.
I don't know if you can set two sets of polygons, overlapping each other ? Just use the same interpolation calculations and generate a second set of polygons just like in the diagram hereafter : you have the red set of polygons built and add the green set by setting the left vertices of a green polygon in the middle of a red polygon, and its right vertices in the middle of the next red polygon.
![diagram][1]
This should work on concave curves and... well you should be flying over the convex ones anyway.
If this doesn't work try setting a big number of polygons to build the slope. Use a tenth of the circle's radius for the polygon's width, maybe even less. That should reduce your slope discontinuities.
-- Edit
In Box2D.js line 5082 (in this repo at least) you have the PreSolve(contact, manifold) function that you can override to check if the manifolds (directions in which the snowball are impulsed when colliding the polygons) are correct.
To do so, you would need to recover the manifold vector and compare it to the normal of the curve. It should look like that (maybe not exactly) :
Box2D.Dynamics.b2ContactListener.prototype.PreSolve = function (contact, oldManifold) {
// contact instanceof Box2D.Dynamics.Contacts.b2Contact == true
var localManifold, worldManifold, xA, xB, man_vect, curve_vect, normal_vect, angle;
localManifold = contact.GetManifold();
if(localManifold.m_pointCount == 0)
return; // or raise an exception
worldManifold = new Box2D.Collision.b2WorldManifold();
contact.GetWorldManifold( worldManifold );
// deduce the impulse direction from the manifold points
man_vect = worldManifold.m_normal.Copy();
// we need two points close to & surrounding the collision to compute the normal vector
// not sure this is the right order of magnitude
xA = worldManifold.m_points[0].x - 0.1;
xB = worldManifold.m_points[0].x + 0.1;
man_vect.Normalize();
// now we have the abscissas let's get the ordinate of these points on the curve
// the subtraction of these two points will give us a vector parallel to the curve
var SmoothConfig;
SmoothConfig = {
params: {
method: 'cubic',
clip: 'mirror',
cubicTension: 0,
deepValidation: false
},
options: {
averageLineLength: .5
}
}
// get the points, smooth and smooth config stuff here
smooth = Smooth(global_points,SmoothConfig);
curve_vect = new Box2D.Common.Math.b2Vec2(xB, smooth(xB)[1]);
curve_vect.Subtract(new Box2D.Common.Math.b2Vec2(xA, smooth(xA)[1]));
// now turn it to have a normal vector, turned upwards
normal_vect = new Box2D.Common.Math.b2Vec2(-curve_vect.y, curve_vect.x);
if(normal_vect.y > 0)
normal_vect.NegativeSelf();
normal_vect.Normalize();
worldManifold.m_normal = normal_vect.Copy();
// and finally compute the angle between the two vectors
angle = Box2D.Common.Math.b2Math.Dot(man_vect, normal_vect);
$('#angle').text("" + Math.round(Math.acos(angle)*36000/Math.PI)/100 + "°");
// here try to raise an exception if the angle is too big (maybe after a few ms)
// with different thresholds on the angle value to see if the bumps correspond
// to a manifold that's not normal enough to your curve
};
I'd say the problem has been tackled in Box2D 2.2.0 , see its manual, section 4.5 "Edge Shapes"
The thing is it's a feature of the 2.2.0 version, along with the chainshape thing, and the box2dweb is actually ported from 2.2.1a - don't know about box2dweb-closure.
Anything I've tried by modifying Box2D.Collision.b2Collision.CollidePolygonAndCircle has resulted in erratic behaviour. At least a part of the time (e.g. ball bumping in random directions, but only when it rolls slowly).

Categories

Resources