📜 ⬆️ ⬇️

Random Cat Generator in 8 Steps


Good time, Habr!
I always loved cats, and loved to draw them, especially cat faces. You will slightly change the form, the line - and a completely different expression, a different mood. My A4 sheets were outlined under the limit. And then I recently hit my head - and what if I make a generator of muzzles of cats? To click on the button and you random cat muzzle will be thrown out. As much as possible random and interesting. Let's see how to make such a thing.
I ask under the cat, lovers of cats.

We’ll do everything on JS and Canvas, and I don’t provide initialization code, settings, and the like. This is complete on the Internet, but we are also interested in how to draw cats, right?

Here are just a few predefined functions, just for further convenience, here they are:

function add(func, scale){ Graphics.ctx.scale(scale.x, scale.y); func(Graphics.ctx); Graphics.ctx.scale(1, 1); } 

Change the size of the canvas, draw something, return it back.
')
 function drawircle(ctx, pos, radius, fillColor, strokeColor, lineWidth) { ctx.beginPath(); ctx.arc(center.x - pos.x, center.y + pos.y, radius, 0, 2*Math.PI, false); ctx.fillStyle = fillColor; ctx.fill(); ctx.lineWidth = lineWidth; ctx.strokeStyle = strokeColor; ctx.stroke(); } 


And this drawing circles \ circles. Also nothing special, all this can be read millions of times and on Habré and anywhere, let's rather to the cats!

Step 1 - Head


We start with the head. Sho i am the head? Circle. Which can be slightly compressed, or expanded.
You can also set the thickness of the stroke, we'll do that too. And there is a small detail, look at the comments in the code.
The code is all commented, I think there’s no problem with understanding.

 //   var radius = Math.sRandom(60, 70); //  var scaleCircle = {x:Math.sRandom(1,1.1),y:Math.sRandom(0.9,1.0)}; //  var whiteColor = "#fff"; var blackColor = "#000"; // add(function(ctx){ // (Math.sRandom(0, 100) < 95 ? blackColor : whiteColor) -  , , ,   , ..    . ,   . drawircle(ctx, {x:0,y:0}, radius, whiteColor, (Math.sRandom(0, 100) < 95 ? blackColor : whiteColor), Math.sRandom(2,5)); }, scaleCircle); 


Vot and head appeared.



Go ahead!

Step 2 - Ears


Cats' ears are one of the most expressive elements of the muzzle. Therefore, the more the ears are different, differently turned, of different widths, the greater will be the variety of expressions.
We do.

  //,   ,     var dir = {x:0, y:radius}; //  var angleOne = Math.PI + Math.PI/Math.sRandom(2, 5); //      var pointR1 = VectorRot(dir, angleOne); //  ,         var pointR2 = VectorRot(dir, angleOne - Math.PI/Math.sRandom(4, 7)); //    var topPointR = {x:((pointR1.x + pointR2.x) / 2)+Math.sRandom(-10, 10), y:pointR2.y - 30 + Math.sRandom(0, 5)}; // add(function(ctx){ //   ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor; ctx.lineWidth = Math.sRandom(2, 4); topPointR = {x:topPointR.x+Math.sRandom(-1,5), y:topPointR.y+Math.sRandom(-5,5)}; ctx.moveTo(center.x + pointR1.x,center.y + pointR1.y); ctx.lineTo(center.x + topPointR.x,center.y + topPointR.y); ctx.lineTo(center.x + pointR2.x,center.y +pointR2.y); ctx.fill(); ctx.stroke(); //   ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor; ctx.lineWidth = Math.sRandom(2, 4); var topPointL = VectorXInvert({x:topPointR.x+Math.sRandom(-5,5), y:topPointR.y+Math.sRandom(-5,5)}); var pointL1 = VectorXInvert(pointR1); var pointL2 = VectorXInvert(pointR2); ctx.moveTo(center.x + pointL1.x,center.y + pointL1.y); ctx.lineTo(center.x + topPointL.x,center.y + topPointL.y); ctx.lineTo(center.x + pointL2.x,center.y +pointL2.y); ctx.fill(); ctx.stroke(); }, {x:1,y:1}); 


Iiiii's what we got:



Already resembles a cat, right?

Step 3 - Mustache


The second in expressiveness, after the ears, is the element of the cat's muzzle. Making it is not difficult, but making it look more likely to be more difficult. You can't get by with one random move, you have to twist the cycle, and calculate points on the counter, for more linear results.

  //    //  ,        // -    var pointsR = []; //   var count = Math.floor(Math.sRandom(3, 5)); for (var i = 0; i < count; i++) { // ,      /    var dir = {x:0, y:radius/Math.sRandom(1.6,1.9)}; // ,   ,   var angleOne = Math.PI/(2 + ((i+1)/4)); //  var pointR1 = VectorRot(dir, angleOne); // y  ,     count      //      var y = pointR1.y+(i < count / 2 ? -Math.sRandom(8, 25) : Math.sRandom(7, 15) ); //       pointsR.push({begin:pointR1, end:{x:pointR1.x - Math.sRandom(60, 100),y:y}}); } //    var lineWidth = Math.sRandom(0.5, 2); // add(function(ctx){ //  for (var i = 0; i < pointsR.length; i++) { ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor; ctx.lineWidth = lineWidth; ctx.moveTo(center.x - pointsR[i].begin.x,center.y + pointsR[i].begin.y); ctx.lineTo(center.x - pointsR[i].end.x,center.y + pointsR[i].end.y); ctx.stroke(); } //  for (var i = 0; i < pointsR.length; i++) { ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor; ctx.lineWidth = lineWidth; var pointLBegin = VectorXInvert(pointsR[i].begin); var pointLEnd = VectorXInvert(pointsR[i].end); ctx.moveTo(center.x - pointLBegin.x,center.y + pointLBegin.y); ctx.lineTo(center.x - pointLEnd.x,center.y + pointLEnd.y); ctx.stroke(); } }, {x:1,y:1}); 


Do not be confused by the VectorXInvert function, you just often had to reflect various elements on x, so a simple function was made that makes x = -x;

We look as our cat is drawn:



Step 4 - Mouth


It is quite difficult to make it realistic, so we’ll just make a line of the mouth, schematically, but for our graphic design it’s fine.
We write the code that draws the line of the mouth. Made on Bezier curves.

  //--- //     .    + 2    // P0 // P3 | iP3 // | | | // P2--P1--iP2 var P0 = {x:center.x, y:center.y}; var P1 = {x:center.x, y:center.y + Math.sRandom(40, 65)}; var P2 = {x:center.x - Math.sRandom(29, 36),y: center.y + 40}; var P3 = {x:center.x - Math.sRandom(20, 40), y:center.y + Math.sRandom(23, 28)}; var iP2 = {x:center.x + Math.sRandom(29, 36),y: center.y + 40}; var iP3 = {x:center.x + Math.sRandom(20, 40), y:center.y + Math.sRandom(23, 28)}; // add(function(ctx){ ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor ; ctx.lineWidth = Math.sRandom(1,3); ctx.moveTo(P0.x,P0.y ); ctx.bezierCurveTo(P1.x, P1.y, P2.x, P2.y, P3.x, P3.y); ctx.stroke(); ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = fillColor ; ctx.lineWidth = Math.sRandom(1,3); ctx.moveTo(P0.x,P0.y ); ctx.bezierCurveTo(P1.x, P1.y, iP2.x, iP2.y, iP3.x, iP3.y); ctx.stroke(); }, {x:1,y:1}); 


We look at what happened. Patience, still a little bit left!


Step 5 - Nose


The nose is the nose. We make it in two options - a small circle and a triangle. The circle will appear much less frequently. Well, so for interest.
Of course, we mix in randomly, including colors, so that different noses are obtained - painted over, and just a contour. Do we need a lot of cats?

  //   -  ,   var chance = Math.sRandom(0, 100); if(chance < 98) { //  var scale = {x:Math.sRandom(0.9,1.3), y:Math.sRandom(0.9,1.3)}; //  var pointR ={x:Math.sRandom(4,5)*scale.x,y:Math.sRandom(-5,-4)*scale.y}; //  var pointL ={x:Math.sRandom(-4,-5)*scale.x,y:Math.sRandom(-5,-4)*scale.y}; //  var bottomPoint ={x:0,y:Math.sRandom(5,6)*scale.y}; // add(function(ctx){ ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = (Math.sRandom(0, 100) > 50 ? fillColor : strokeColor); ctx.lineWidth = Math.sRandom(1,3); ctx.moveTo(center.x + pointR.x,center.y + 5 + pointR.y); ctx.lineTo(center.x + bottomPoint.x,center.y + 5 + bottomPoint.y); ctx.lineTo(center.x + pointL.x,center.y + 5 + pointL.y); ctx.closePath(); ctx.fill(); ctx.stroke(); }, {x:1,y:1}); } else { //  add(function(ctx){ drawircle(ctx, {x:0,y:0}, Math.sRandom(7, 10), strokeColor, strokeColor, 1); }, {x:1,y:1}); } 


Our cat gradually turns into a cat. This is good news.



Step 6 - Eyes


Eyes thing complicated. No, drawing is not difficult - just two Bezier curves. But we must also add a closing eyes, the cat can sleep, and maybe one eye slightly open. And it must be done. This time just a cat, without a code. For a large amount, do not want to bore the reader with a bunch of text. At the end will be given the source code, who wants to look. And we just look at what happened.



The cat is already there, but let's add some more decor.

Step 7 - Mustache Points on Cheeks


You know, there are such. The probability of occurrence is natural, not 100%. Here is the code, then the result.
The code is simple - just scatter points at some distance from the nose.

  if(Math.sRandom(0, 100) > 60) { add(function(ctx){ for (var i = 0; i < Math.sRandom(5, 7); i++) { var P = {x:Math.sRandom(20, 40),y:Math.sRandom(0, 30)}; drawircle(ctx, P, 1, strokeColor, strokeColor, 1); } for (var i = 0; i < Math.sRandom(5, 7); i++) { var P = {x:-Math.sRandom(20, 40),y:Math.sRandom(0, 30)}; drawircle(ctx, P, 1, strokeColor, strokeColor, 1); } }, {x:1,y:1}); } 


Result:


Step 8 - “Bangs”


Just sometimes draw a couple of lines on top. In words, it is hard to describe, we look at the code, we see what happens.

 if(Math.sRandom(0, 100) > 75) { add(function(ctx){ for (var i = 0; i < Math.sRandom(3, 5); i++) { //      var radiusVector = {x:0,y:-radius}; //     //       radiusVector = VectorRot(radiusVector, Math.sRandom(-0.01, 0.01)) //   var P0 = {x:Math.sRandom(-25, 25), y: radiusVector.y}; var P1 = {x:Math.sRandom(-25, 25), y: Math.sRandom(-50, -40)}; //  var lineWidth = Math.sRandom(0.5, 1.5); // drawLine(ctx, P0, P1, strokeColor, strokeColor, lineWidth); } }, {x:1,y:1}); } 


Great, right?



Step 8 - Bell or Bow


Well, this is just for fun, I thought to add more, and decided to add a bow and a bell. Do not judge strictly, I have fun :)
As always the code, then beautiful pictures with cats.

  // //    var chanceBottom = Math.sRandom(0, 100); if(chanceBottom > 50) { var chance = Math.sRandom(0, 100); if(chance > 90) { // -   + ,      var P = {x:0,y:radius}; var P0 = {x:Math.sRandom(20, 45), y:radius- Math.sRandom(13, 22)}; var P1 = {x:Math.sRandom(20, 45), y:radius+ Math.sRandom(13, 22)}; add(function(ctx){ var color = (Math.sRandom(0, 100) > 50 ? fillColor : strokeColor); ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = color; ctx.lineWidth = Math.sRandom(2, 5); ctx.moveTo(center.x + Px,center.y + Py); ctx.lineTo(center.x + P0.x,center.y + P0.y); ctx.lineTo(center.x + P1.x,center.y + P1.y); ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = color; ctx.lineWidth = Math.sRandom(2, 5); ctx.moveTo(center.x - Px,center.y + Py); ctx.lineTo(center.x - P0.x,center.y + P0.y); ctx.lineTo(center.x - P1.x,center.y + P1.y); ctx.closePath(); ctx.stroke(); ctx.fill(); drawircle(ctx, P, Math.sRandom(6, 12), (Math.sRandom(0, 100) > 50 ? fillColor : strokeColor), strokeColor, Math.sRandom(1, 3)); }, {x:1,y:1}); } } else { // var chance = Math.sRandom(0, 100); if(chance > 90) { // - ,   .    ,  ,    var P = {x:0,y:radius}; var P0 = {x:Math.sRandom(8, 15), y:radius+ Math.sRandom(23, 29)}; var P1 = {x:-P0.x, y:P0.y}; var P3 = {x:0,y:P0.y + Math.sRandom(0, 7)}; add(function(ctx){ drawircle(ctx, P3, Math.sRandom(2, 6), (Math.sRandom(0, 100) > 50 ? fillColor : strokeColor), strokeColor, Math.sRandom(1, 3)); var color = (Math.sRandom(0, 100) > 50 ? fillColor : strokeColor); ctx.beginPath(); ctx.strokeStyle = strokeColor; ctx.fillStyle = color; ctx.lineWidth = Math.sRandom(2, 5); ctx.moveTo(center.x + Px,center.y + Py); ctx.lineTo(center.x + P0.x,center.y + P0.y); ctx.lineTo(center.x + P1.x,center.y + P1.y); ctx.closePath(); ctx.stroke(); ctx.fill(); }, {x:1,y:1}); } } 


As you can see nothing complicated, just geometric shapes.
The code would be boring if there were no cats, let there be a cat with a bow!



Conclusion


Well, I finished my story about cats.
I quote the code on github: github.com/MagistrAVSH/random-cat
But the result of all the works, you can click: magistravsh.imtqy.com/random-cat
And now scat from the monitor, and stroke the cat! :)

Source: https://habr.com/ru/post/195142/


All Articles