试着画一个书架(可汗学院练习)

Trying to draw a bookshelf (Khan Academy exercise)

本文关键字:练习 一个      更新时间:2023-09-26

我正在做一个基于图书对象数组在画布上绘制书架的练习。具体说明如下:

现在添加更多的书,并使用循环在画布上绘制更多的书架。考虑一下如何使用条件和/或%操作符来做到这一点。

我的代码在循环中包含一个条件,但我似乎不能让它工作。条件在下面代码的最后。

//book array
var books = [{
    title: "The Giver",
    author: "Lois Lowry",
    coverColor: color(214, 255, 219),
    stars: 3
}, {
    title: "The Outsiders",
    author: "S. E. Hinton",
    coverColor: color(255, 127, 127),
    stars: 5
}, {
    title: "Harry Potter",
    author: "J. K. Rowling",
    coverColor: color(135, 193, 255),
    stars: 4
}, {
    title: "Harry Potter",
    author: "J. K. Rowling",
    coverColor: color(135, 193, 255),
    stars: 4
}];
// draw shelf
background(230, 187, 122);
fill(173, 117, 33);
rect(0, 120, width, 10);
// book loop
for (var i = 0; i < books.length; i++) {
    var book = books[i]; //setting book variable
    var xPos = i * 100;
    var yPos = 20;
    fill(book.coverColor);
    rect(xPos + 10, yPos, 90, 100);
    fill(0, 0, 0);
    textSize(11); //general book drawings
    text(book.title, xPos + 15, yPos + 5, 70, 100);
    textSize(9);
    text(book.author, xPos + 20, yPos * 2, 70, 100);
    //Seal of approval
    if (book.stars > 3) {
        var approvalSeal = getImage("cute/Star");
        image(approvalSeal, xPos + 10, yPos * 4, 30, 40);
        text("Seal of approval!", xPos + 45, yPos * 4 + 15, 50, 40);
    }
    //conditional wrap-around
    if (xPos > 350) {
        xPos = i * 100;
        yPos += 120;
    }
}

你应该把这个放在循环之外:

var yPos = 20;

当前您在每次迭代中重置yPos,因此环绕代码永远不会生效。

xPos也有问题。在每次迭代中将其设置为i * 100,这将使其超出架子的末端。当你创建一个新的架子时,你必须重置xPos

正确的方法是初始化xPosyPos,绘制第一个书架,然后开始迭代这些书。增加图书位置,必要时绕行:

function drawShelf(yPos) {
  var saved = context.fillStyle;
  fill(color(173, 117, 33));
  rect(0, yPos + 120, width, 10);
  context.fillStyle = saved;
}
var xPos = 0,
    yPos = 0;
drawShelf(yPos);
for (var i = 0; i < books.length; i++) {
  var book = books[i];
  fill(book.coverColor);
  rect(xPos + 10, yPos + 20, 90, 100);
  xPos += 100;
  if (xPos > 350) {
    xPos = 0;
    yPos += 130;
    drawShelf(yPos);
  }
}

您可以在下面的代码片段中看到该代码的运行。我添加了代码来模拟Processing环境中的绘图命令,并且制作了一打带有随机颜色的图书对象。书的其他属性被省略。

var canvas = document.getElementsByTagName('canvas')[0],
    width = 410,
    height = 400,
    context = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
function background(r, g, b) {
  var saved = context.fillStyle;
  fill(color(r, g, b));
  rect(0, 0, width, height);
  context.fillStyle = saved;
}
function color(r, g, b) {
  return 'rgb(' + r + ', ' + g + ', ' + b + ')';
}
function fill(style) {
  context.fillStyle = style;
}
function rect(x, y, w, h) {
  context.fillRect(x, y, w, h);
}
var books = new Array(12);
for (var i = 0; i < books.length; ++i) {
  books[i] = {
    coverColor: color(
      Math.floor(Math.random() * 256),
      Math.floor(Math.random() * 256),
      Math.floor(Math.random() * 256)
    )
  };
}
background(230, 187, 122);
function drawShelf(yPos) {
  var saved = context.fillStyle;
  fill(color(173, 117, 33));
  rect(0, yPos + 120, width, 10);
  context.fillStyle = saved;
}
var xPos = 0,
    yPos = 0;
drawShelf(yPos);
for (var i = 0; i < books.length; i++) {
  var book = books[i];
  fill(book.coverColor);
  rect(xPos + 10, yPos + 20, 90, 100);
  xPos += 100;
  if (xPos > 350) {
    xPos = 0;
    yPos += 130;
    drawShelf(yPos);
  }
}
<canvas></canvas>

条件不执行任何操作的原因是因为它位于for循环迭代的末尾。对分配的新值不做任何处理,并且在进行下一次迭代时,坐标将恢复到"第一行图书"坐标。在使用它们之前,您需要分配这些坐标。

我绘制我的(丑陋的)书架的方式是只使用%操作符作为x坐标,并对行进行分层除法。对我来说,这似乎比使用条件句更容易。书架可以看作是一个网格,顺序像

0 1 2 
3 4 5 
6 7 8 ... etc

因为您写了350作为限制,我假设您想每行显示3本书。注意x坐标重复出现,像这样

0 100 200
0 100 200
0 100 200

%操作符与正实参一起使用时,返回第一个实参除以第二个实参的余数。使用300作为第二个参数,我得到x坐标的重复序列0、100和200。

现在,行y坐标每3本书增加一次。所以我用数学。floor向下舍入到我想跳转到的确切的整行数,并使用这些值,确定在哪里画这本书。

在我的快速演示中,我只能依赖基本的画布操作。我不熟悉可汗学院提供的工具。

我也不认为你的意思是使用yPos * 2或* 4,因为当你向下移动几行时,这些偏移量会相乘,而不仅仅是向下移动。

     var ctx = document.getElementById("canvas").getContext("2d");
     function color() {}
     function fill(r, g, b) {
     }
     function rect(x, y, w, h) {
       ctx.rect(x, y, w, h);
       ctx.stroke();
     }
     function text(s, x, y, w, h) {
       ctx.beginPath();
       ctx.moveTo(x, y);
       ctx.font = "9px serif";
       ctx.fillText(s, x, y + 15);
       ctx.stroke();
     }
     var books = [{
       title: "The Giver (0)",
       author: "Lois Lowry (0)",
       coverColor: color(214, 255, 219),
       stars: 3
     }, {
       title: "The Outsiders (1)",
       author: "S. E. Hinton (1)",
       coverColor: color(255, 127, 127),
       stars: 5
     }, {
       title: "Harry Potter (2)",
       author: "J. K. Rowling (2)",
       coverColor: color(135, 193, 255),
       stars: 4
     }, {
       title: "Mary Scooter (3)",
       author: "G. Q. Bowling (3)",
       coverColor: color(135, 193, 255),
       stars: 4
     }, {
       title: "The Brothers Karmazoov (4)",
       author: "F. Downstoveeski (4)",
       coverColor: color(214, 255, 219),
       stars: 3
     }, {
       title: "The Unbearable Brightness of Skiing (5)",
       author: "Milano Counter (5)",
       coverColor: color(255, 127, 127),
       stars: 5
     }, {
       title: "The Uber Gatsby (6)",
       author: "Scot-Free Fitzgee (6)",
       coverColor: color(135, 193, 255),
       stars: 4
     }, {
       title: "Catch-42 (7)",
       author: "Joe Keller (7)",
       coverColor: color(135, 193, 255),
       stars: 4
     }, {
       title: "Focker's Pendulum (8)",
       author: "Umbrella Ekoh (8)",
       coverColor: color(214, 255, 219),
       stars: 3
     }, {
       title: "The Tiny Princess (9)",
       author: "Anthony St. Expert (9)",
       coverColor: color(255, 127, 127),
       stars: 5
     }, {
       title: "Of Fire and Ice (10)",
       author: "George Martinelli (10)",
       coverColor: color(135, 193, 255),
       stars: 4
     }];
      // draw shelf
      // background(230, 187, 122);
      // fill(173, 117, 33);
      // rect(0, 120, width, 10);
      // book loop
     for (var i = 0; i < books.length; i++) {
       var book = books[i]; //setting book variable
       // DETERMINE WHERE TO PLACE TOP-LEFT BOOK CORNER 
       var xPos = (i * 100 % 300);
       var yPos = 20 + 120 * Math.floor(i / 3);
       // var xPos = i*100;
       // var yPos = 20;
       // fill(book.coverColor);
       rect(xPos + 10, yPos, 90, 100);
       // fill(0, 0, 0);
       // textSize(11);//general book drawings
       text(book.title, xPos + 15, yPos + 5, 70, 100);
       // textSize(9);
       text(book.author, xPos + 20, yPos + 25, 70, 100);
       //Seal of approval
       if (book.stars > 3) {
         // var approvalSeal = getImage("cute/Star");
         // image(approvalSeal,xPos+10, yPos*4, 30, 40);
         text("Seal of approval!", xPos + 45, yPos + 40 + 15, 50, 40);
       }
       //conditional wrap-around
       // if(xPos > 350) {
       //   xPos = i*100;
       // yPos += 120;
       // }
     }
<canvas id="canvas" width="450" height="600">
</canvas>