【问题标题】:How to change the center of background's rotation on my canvas?如何更改画布上背景的旋转中心?
【发布时间】:2019-08-30 12:44:19
【问题描述】:

我正在开发一个类似于游戏(如 gta v)小地图的项目,但要跟踪用户在场地上的移动。该字段为 2K 图像,用户由黑色三角形表示。但是三角形位于场地的底部,而不是中心。并旋转背景(当用户转动时)我正在使用此答案帖子中的代码:Bryan Field's answer,它工作得很好,但锚的旋转在中心,我希望它在三角形上,但我可以'不要弄清楚数学来做到这一点(以不破坏背景图像界限的方式)。三角形位置是(canvas.width/2,canvas.height-100),旋转的锚点在(canvas.width/2,canvas.height/2)。这是一个屏幕截图:

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    const ctx = document.querySelector('canvas').getContext('2d');
    const mapImage = new Image();
    mapImage.onload = start;
    mapImage.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Map_of_the_Battle_of_the_Somme%2C_1916.svg/1568px-Map_of_the_Battle_of_the_Somme%2C_1916.svg.png';
    
    // wedge pointing left
    const playerPath = new Path2D();
    playerPath.lineTo(15, 0);
    playerPath.lineTo(-15, 10);
    playerPath.lineTo(-15, -10);
    playerPath.closePath();
    
    function start() {
      const keys = {};
      const player = {
        x: mapImage.width / 2,
        y: mapImage.height / 2,
        turnVel: Math.PI / 2,  // 1/4 turn per second
        dir: -Math.PI / 2,
        vel: 10,  // 10 units per second
      };
      
      let then = 0;
      function render(now) {
        now *= 0.001; // convert to seconds
        const deltaTime = now - then;
        then = now;
        
        resizeCanvasToDisplaySize(ctx.canvas);
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        
        let turnDir = 0;
        if (keys[37]) {
          turnDir = -1;
        } else if (keys[39]) {
          turnDir = 1;
        }
        player.dir += player.turnVel * turnDir * deltaTime;
          
        player.x += Math.cos(player.dir) * player.vel * deltaTime;
        player.y += Math.sin(player.dir) * player.vel * deltaTime;
     
        ctx.save();
        {
          // move origin to bottom center of canvas
          ctx.translate(ctx.canvas.width / 2, ctx.canvas.height * 0.9);
        
          ctx.save();
          {
            // rotate origin opposite of player
            // the -Math.PI/2 is because the code above adding the direction
            // to the velocity has dir = 0 meaning going east. 
            // We want to face up the map. Up is -Math.PI/2
            // so when going up we need the rotation here to be 0. (not rotated)
            ctx.rotate(-player.dir - Math.PI/ 2);
            
            // move origin based on player's position
            ctx.translate(-player.x, -player.y);
          
            ctx.drawImage(mapImage, 0, 0);
    
            // draw enemies or targets here. They are in map coordinates
            // example
            ctx.fillStyle = 'red';
            for (let y = 0; y < mapImage.height; y += 200) {
              for (let x = 0; x < mapImage.width; x += 200) {
                ctx.save();
                {
                  ctx.translate(x, y);
                  ctx.rotate(Math.atan2(player.y - y, player.x - x));
                  ctx.fill(playerPath);
                }
                ctx.restore();
              }
            }
          } 
          ctx.restore();  // origin back at bottom center of canvas
          
          // draw Player
          ctx.save();
          {
            ctx.rotate(-Math.PI / 2);  // because the player's shape points left
            ctx.fillStyle = 'black';
            ctx.fill(playerPath);
          }
          ctx.restore();
        }
        ctx.restore();  // origin back at top left corner of canvas
        
        requestAnimationFrame(render);
      }
      requestAnimationFrame(render);
      
      window.addEventListener('keydown', (e) => {
        keys[e.keyCode] = true;
      });
      window.addEventListener('keyup', (e) => {
        keys[e.keyCode] = false;
      });
      
      function resizeCanvasToDisplaySize(canvas) {
        const width = canvas.clientWidth;
        const height = canvas.clientHeight;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
          canvas.width = width;
          canvas.height = height;
        }
        return needResize;
      }
    }
    body { margin: 0; }
    canvas { width: 100vw; height: 100vh; display: block; }
    #info {
      position: absolute;
      left: 1em;
      top: 1em;
      color: white;
      background: rgba(0, 0, 0, 0.5);
      padding: 0.5em;
    }
    <canvas></canvas>
    <div id="info">use cursor left/right</div>

    注意:最好跳过ctx.savectx.restore 而使用ctx.setTransform 来提高速度。

    【讨论】:

    • 我正在分析这段代码好几天了,但我无法理解它的一些内容。因为看起来几乎正是我所需要的,所以我会问你哥们。 1 - 为什么渲染函数中有这么多括号?不知道 JS 上的那种语法。 2 - 在我的项目中不是我需要的动画,它按需移动背景,通过新的三角形“x,y”坐标(作为笛卡尔轴)。我怎样才能使代码适应它。 3 - 当到达图像的边界时要做什么,在这段代码中,只需将它从边缘传递到白色。发生这种情况时我可以重复瓷砖吗?
    • 1.额外的括号只是样式。当我保存和恢复上下文时,我用它们来标记。在每对括号内,画布的原点被移动/旋转/缩放。 2. 如果您不需要动画,请删除对requestAnimationFrame 的调用。绘图的唯一输入是 player.x、player.y 和 player.dir。 3. 评论的答案太大了,问一个新问题
    猜你喜欢
    • 2014-03-01
    • 2019-12-21
    • 2017-03-15
    • 1970-01-01
    • 2011-07-10
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多