使用我的像素艺术程序时出现奇怪的视觉错误

Weird visual bug when using my pixel art program

如标题所述,我的像素艺术程序不断出现一个奇怪的视觉错误。当我使用 pushMatrix()scale()popMatrix() 缩小时。我无法真正描述这个错误,所以我得到了它的屏幕截图(错误是像素之间奇怪的白线)。

代码:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Pixel Art Drawer & Importer</title>
</head>

<body>
  <canvas id="mycanvas"></canvas>

  <input type="text" id="color1" value="100" maxlength="3">
  <input type="text" id="color2" value="100" maxlength="3">
  <input type="text" id="color3" value="100" maxlength="3">
  <p>You can import the pixel art textures into a game or program with this <a href="https://www.khanacademy.org/computer-programming/example-pixel-art/5355812004872192">code</a>.</p>
  <script src="https://cdn.jsdelivr.net/processing.js/1.4.8/processing.min.js"></script>
  <script>
    var sketchProc = function(processingInstance) {
      with(processingInstance) {
        size(400, 400);
        frameRate(30);
        // HOW TO USE
        // Pick a grid size with the grid variable below
        // Change the color variable below to whatever
        // There is no eraser, becaue I couldn't figure out how to make it work.

        var gridSize = 16;

        var pixels = [];
        var alreadyExists;
        var color1 = document.getElementById('color1');
        var color2 = document.getElementById('color2');
        var color3 = document.getElementById('color3');

        background(255, 255, 255);
        for (var i = 0; i < gridSize; i++) {
          stroke(0, 0, 0);
          line(400 / gridSize * i, 0, 400 / gridSize * i, 400);
          line(0, 400 / gridSize * i, 400, 400 / gridSize * i);
        }

        var update = function() {
          background(255, 255, 255);
          for (var i = 0; i < gridSize; i++) {
            stroke(0, 0, 0);
            line(400 / gridSize * i, 0, 400 / gridSize * i, 400);
            line(0, 400 / gridSize * i, 400, 400 / gridSize * i);
          }
          for (var i = 0; i < pixels.length; i++) {
            noStroke();
            pushMatrix();
            scale(0.5);
            fill(pixels[i][2][0], pixels[i][2][1], pixels[i][2][2]);
            rect(pixels[i][0] * (400 / gridSize), pixels[i][1] * (400 / gridSize), 400 / gridSize, 400 / gridSize);
            popMatrix();
          }
          document.getElementById("output").innerHTML = pixels;
        };

        var mousePressed = mouseDragged = function() {
          alreadyExists = false;
          closestPixel = [ceil(mouseX / (400 / gridSize)) - 1, ceil(mouseY / (400 / gridSize)) - 1, [color1.value, color2.value, color3.value]];

          for (var i = 0; i < pixels.length; i++) {
            if (samePixels(pixels[i], closestPixel)) {
              alreadyExists = true;
              pixels[i][2] = [color1.value, color2.value, color3.value];

              break;
            }
          }

          if (!alreadyExists) {
            pixels.push(closestPixel);
          }
          update();
        };

        var samePixels = function(p1, p2) {
          var samePosition = p1[0] === p2[0] && p1[1] === p2[1];

          if (!samePosition) {
            return false;
          }

          return true;
        };

      }
    };

    var canvas = document.getElementById("mycanvas");
    // Pass the function sketchProc (defined in myCode.js) to Processing's constructor.
    var processingInstance = new Processing(canvas, sketchProc);
  </script>
  <p id="output" style="color:red">This is where the output will appear.</p>
</body>

</html>

看起来像是程序按照您的要求执行,而不是您希望它执行的情况:)

您使用的 pushMatrix() / scale() / popMatrix() 部分适用于每个“像素”块的呈现方式(包括您注意到的笔划),但不会影响任何鼠标光标逻辑.

一个选择是将 rect() x、y 值和大小简单地减半:

例如

for (var i = 0; i < pixels.length; i++) {
            noStroke();
            // pushMatrix();
            // scale(0.5);
            fill(pixels[i][2][0], pixels[i][2][1], pixels[i][2][2]);
            rect(pixels[i][0] * (400 / gridSize) / 2, pixels[i][1] * (400 / gridSize) / 2, 400 / gridSize / 2, 400 / gridSize / 2);
            // popMatrix();
          }

注意上面只是 update() 中的相关 for 循环:希望这个想法得到了清楚的说明。

您还可以在整个代码中考虑这个比例,包括鼠标交互(可以约束):

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Pixel Art Drawer & Importer</title>
</head>

<body>
  <canvas id="mycanvas"></canvas>

  <input type="text" id="color1" value="100" maxlength="3">
  <input type="text" id="color2" value="100" maxlength="3">
  <input type="text" id="color3" value="100" maxlength="3">
  <p>You can import the pixel art textures into a game or program with this <a href="https://www.khanacademy.org/computer-programming/example-pixel-art/5355812004872192">code</a>.</p>
  <script src="https://cdn.jsdelivr.net/processing.js/1.4.8/processing.min.js"></script>
  <script>
    var sketchProc = function(processingInstance) {
      with(processingInstance) {
        size(400, 400);
        var scaleFactor = 0.5;
        var gridWidth   = width * scaleFactor;
        var gridHeight  = height * scaleFactor;
        frameRate(30);
        // HOW TO USE
        // Pick a grid size with the grid variable below
        // Change the color variable below to whatever
        // There is no eraser, becaue I couldn't figure out how to make it work.

        var gridSize = 16;

        var pixels = [];
        var alreadyExists;
        var color1 = document.getElementById('color1');
        var color2 = document.getElementById('color2');
        var color3 = document.getElementById('color3');

        var update = function() {
          background(255, 255, 255);
          for (var i = 0; i < gridSize; i++) {
            stroke(0, 0, 0);
            line(gridWidth / gridSize * i, 0, gridWidth / gridSize * i, gridWidth);
            line(0, gridHeight / gridSize * i, gridHeight, gridHeight / gridSize * i);
          }
          for (var i = 0; i < pixels.length; i++) {
            noStroke();
            // pushMatrix();
            // scale(0.5);
            fill(pixels[i][2][0], pixels[i][2][1], pixels[i][2][2]);
            rect(pixels[i][0] * (gridWidth / gridSize), 
                 pixels[i][1] * (gridHeight / gridSize) , 
                 gridWidth / gridSize , gridHeight / gridSize);
            // popMatrix();
          }
          document.getElementById("output").innerHTML = pixels;
        };

        var mousePressed = mouseDragged = function() {
          mouseX = constrain(mouseX, 0, gridWidth);
          mouseY = constrain(mouseY, 0, gridHeight);
          alreadyExists = false;
          closestPixel = [ceil(mouseX / (gridWidth / gridSize)) - 1, 
                          ceil(mouseY / (gridHeight / gridSize)) - 1, 
                          [color1.value, color2.value, color3.value]];

          for (var i = 0; i < pixels.length; i++) {
            if (samePixels(pixels[i], closestPixel)) {
              alreadyExists = true;
              pixels[i][2] = [color1.value, color2.value, color3.value];

              break;
            }
          }

          if (!alreadyExists) {
            pixels.push(closestPixel);
          }
          update();
        };

        var samePixels = function(p1, p2) {
          var samePosition = p1[0] === p2[0] && p1[1] === p2[1];

          if (!samePosition) {
            return false;
          }

          return true;
        };

      }
    };

    var canvas = document.getElementById("mycanvas");
    // Pass the function sketchProc (defined in myCode.js) to Processing's constructor.
    var processingInstance = new Processing(canvas, sketchProc);
  </script>
  <p id="output" style="color:red">This is where the output will appear.</p>
</body>

</html>