RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 909690
Accepted
pank
pank
Asked:2020-11-21 22:15:29 +0000 UTC2020-11-21 22:15:29 +0000 UTC 2020-11-21 22:15:29 +0000 UTC

如何为 HTML 5 Canvas 实现游戏相机(相机放大/缩小)?

  • 772

实际上,任务是实现一个相机,它可以跟随游戏世界中的玩家,并能够从玩家放大/缩小相机。

跟随播放器实现相机非常简单:

ctx.save();
ctx.translate(-camera.leftTopPos.x, -camera.leftTopPos.y);
// Рисуем игрока и игровой мир
ctx.restore();

它在哪里camera:

var camera = {
  leftTopPos: { x: 0, y: 0 }, // Левый верхний угол камеры в игровом мире.
  size: { x: 0, y: 0 }, // Размер камеры (по умолчанию, равен размеру холста)
  scale: 1,
};

ctx.translate用于大型游戏世界是否正确?就性能而言,将玩家始终保持在一个点上,(0, 0)还是(w/2, h/2)相对于他移动所有其他对象会更有效吗?

添加相机放大/缩小的问题。如果你这样做:

ctx.translate(-camera.leftTopPos.x, -camera.leftTopPos.y);
ctx.scale(camera.scale.x, camera.scale.y);

那么改变相机的大小就会出现问题,它会在某个地方移动。

我做了一个在jsfiddle上使用相机的例子。

wasd- 移动相机。 zx- 放大和缩小相机。

function p(s) { document.body.innerHTML += s + '<br>'; }

var w, h;
var camera = {
  leftTopPos: { x: 0, y: 0 },
  size: { x: 0, y: 0 },
  scale: 1,
};
var canvas = document.querySelector('canvas');
var can = canvas;
var context = canvas.getContext('2d');
var ctx = context;

function updateCameraSize() {
	camera.size = {
  	x: canvas.width,
    y: canvas.height,
  };
}

function setFullscreenSize() {
  w = canvas.width = window.innerWidth;
  h = canvas.height = window.innerHeight;
  updateCameraSize();
}

function makeAlwaysCanvasFullscreen() {
  setFullscreenSize();
  window.addEventListener('resize', setFullscreenSize);
}

function drawLine(x1, y1, x2, y2) {
	ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);
  ctx.stroke();
}

function drawGrid() {
  var cellSize = 100;
  var minX = -1000, maxX = 1000;
  var minY = -1000, maxY = 1000;
  for (var x = minX; x <= maxX; x += cellSize) {
    drawLine(x, minY, x, maxY);
  }
  for (var y = minY; y <= maxY; y += cellSize) {
    drawLine(minX, y, maxX, y);
  }
}

function drawAxises() {
  var minX = -1000, maxX = 1000;
  var minY = -1000, maxY = 1000;
  ctx.save();
  ctx.lineWidth = 5;
  ctx.strokeStyle = 'red';
  drawLine(0, 2 * minY, 0, 2 * maxY);
  ctx.strokeStyle = 'green';
  drawLine(2 * minX, 0, 2 * maxX, 0);
  ctx.restore();
}

function update() {
  var dir = { x: 0, y: 0 };
  var speed = 10;
  if (key.isPressed('a')) dir.x -= 1;
  if (key.isPressed('d')) dir.x += 1;
  if (key.isPressed('w')) dir.y -= 1;
  if (key.isPressed('s')) dir.y += 1;
  camera.leftTopPos.x += speed * dir.x;
  camera.leftTopPos.y += speed * dir.y;
}

function draw() {
	ctx.clearRect(0, 0, w, h);
  ctx.save();
  ctx.translate(-camera.leftTopPos.x, -camera.leftTopPos.y);
  ctx.scale(camera.scale, camera.scale);
  drawGrid();
  drawAxises();
  drawViewportRect();
  ctx.restore();
}

function drawViewportRect() {
  ctx.save();
  ctx.lineWidth = 10;
  ctx.strokeStyle = 'yellow';
  var pos = camera.leftTopPos, sz = camera.size;
  ctx.beginPath();
  ctx.rect(pos.x, pos.y, sz.x, sz.y);
  ctx.stroke();
  ctx.restore();
}

function main() {
  function go() {
  	update();
    draw();
    requestAnimationFrame(go);
  }
  requestAnimationFrame(go);
}

makeAlwaysCanvasFullscreen();
main();

key('z', () => {
	camera.scale += 0.1;
});
key('x', () => {
	camera.scale -= 0.1;
});
canvas {
  position: fixed;
  left: 0;
  top: 0;
  /* border: 1px solid black; */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/keymaster/1.6.1/keymaster.min.js"></script>
<canvas></canvas>

html5
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    pank
    2020-11-22T14:45:29Z2020-11-22T14:45:29Z

    使用调试时戳测距离的方法,我还是找到了如何实现相机的放大和缩小:

    ctx.save();
    ctx.translate(-camera.leftTopPos.x * camera.scale, -camera.leftTopPos.y * camera.scale);
    // Рисуем игрока и игровой мир
    ctx.restore();
    

    腔室的尺寸如下:

    camera.size = {
      x: canvas.width / camera.scale,
      y: canvas.height / camera.scale,
    };
    

    jsfiddle

    function p(s) { document.body.innerHTML += s + '<br>'; }
    
    var w, h;
    var camera = {
      leftTopPos: { x: 0, y: 0 },
      size: { x: 0, y: 0 },
      scale: 1,
    };
    var canvas = document.querySelector('canvas');
    var can = canvas;
    var context = canvas.getContext('2d');
    var ctx = context;
    
    function updateCameraSize() {
      camera.size = {
        x: canvas.width / camera.scale,
        y: canvas.height / camera.scale,
      };
    }
    
    function setFullscreenSize() {
      w = canvas.width = window.innerWidth;
      h = canvas.height = window.innerHeight;
      updateCameraSize();
    }
    
    function makeAlwaysCanvasFullscreen() {
      setFullscreenSize();
      window.addEventListener('resize', setFullscreenSize);
    }
    
    function drawLine(x1, y1, x2, y2) {
      ctx.beginPath();
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.stroke();
    }
    
    function drawGrid() {
      var cellSize = 100;
      var minX = -1000, maxX = 1000;
      var minY = -1000, maxY = 1000;
      for (var x = minX; x <= maxX; x += cellSize) {
        drawLine(x, minY, x, maxY);
      }
      for (var y = minY; y <= maxY; y += cellSize) {
        drawLine(minX, y, maxX, y);
      }
    }
    
    function drawAxises() {
      var minX = -1000, maxX = 1000;
      var minY = -1000, maxY = 1000;
      ctx.save();
      ctx.lineWidth = 5;
      ctx.strokeStyle = 'red';
      drawLine(0, 2 * minY, 0, 2 * maxY);
      ctx.strokeStyle = 'green';
      drawLine(2 * minX, 0, 2 * maxX, 0);
      ctx.restore();
    }
    
    function update() {
      var dir = { x: 0, y: 0 };
      var speed = 10;
      if (key.isPressed('a')) dir.x -= 1;
      if (key.isPressed('d')) dir.x += 1;
      if (key.isPressed('w')) dir.y -= 1;
      if (key.isPressed('s')) dir.y += 1;
      camera.leftTopPos.x += speed * dir.x;
      camera.leftTopPos.y += speed * dir.y;
    }
    
    function draw() {
      ctx.clearRect(0, 0, w, h);
      ctx.save();
      ctx.translate(-camera.leftTopPos.x * camera.scale, -camera.leftTopPos.y * camera.scale);
      ctx.scale(camera.scale, camera.scale);
      drawGrid();
      drawAxises();
      drawViewportRect();
      ctx.restore();
    }
    
    function drawViewportRect() {
      ctx.save();
      ctx.lineWidth = 10;
      ctx.strokeStyle = 'yellow';
      var pos = camera.leftTopPos, sz = camera.size;
      ctx.beginPath();
      ctx.rect(pos.x, pos.y, sz.x, sz.y);
      ctx.stroke();
      ctx.restore();
    }
    
    function main() {
      function go() {
        update();
        draw();
        requestAnimationFrame(go);
      }
      requestAnimationFrame(go);
    }
    
    makeAlwaysCanvasFullscreen();
    main();
    
    key('z', () => {
      camera.scale += 0.1;
      updateCameraSize();
    });
    key('x', () => {
      camera.scale -= 0.1;
      updateCameraSize();
    });
    canvas {
      position: fixed;
      left: 0;
      top: 0;
      /* border: 1px solid black; */
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/keymaster/1.6.1/keymaster.min.js"></script>
    <canvas></canvas>

    但性能问题仍然是相关的translate。

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5