HTML5 холст камеры/просмотра - как на самом деле сделать это?

Я'м уверена, что это был солвен 1000 раз, прежде чем: у меня есть холст размером 960560 и номер в размер 50003000 из которых всегда только 960*560 должны быть сделаны, в зависимости от того, где игрок находится. Игрок должен быть всегда в середине, но когда рядом с границами - то лучший вид должен быть рассчитан). Игрок может перемещаться полностью свободно с WASD или клавиши со стрелками. И все объекты должны двигаться сами - вместо того, что я двигаюсь все остальное, но игроку создавать иллюзию, что игрок движется.

Сейчас я нашел эти два вопросы:

https://stackoverflow.com/questions/11464550/html5-creating-a-viewport-for-canvas работает, но только для этого типа игры, я могу'т воспроизводить код для шахты.

https://stackoverflow.com/questions/8592872/changing-the-view-center-of-an-html5-canvas представляется более перспективным, а также perfomant, но я только понимаю для рисования все объекты правильно по отношению к игроку, а не как свиток холста просмотра по отношению к игроку, которого я хочу добиться во-первых конечно.

Мой код (упрощенный - логическая игра отдельно):

var canvas = document.getElementById("game");
canvas.tabIndex = 0;
canvas.focus();
var cc = canvas.getContext("2d");

// Define viewports for scrolling inside the canvas

/* Viewport x position */   view_xview = 0;
/* Viewport y position */   view_yview = 0;
/* Viewport width */        view_wview = 960;
/* Viewport height */       view_hview = 560;
/* Sector width */          room_width = 5000;
/* Sector height */         room_height = 3000;

canvas.width = view_wview;
canvas.height = view_hview;

function draw()
{
    clear();
    requestAnimFrame(draw);

    // World's end and viewport
    if (player.x < 20) player.x = 20;
    if (player.y < 20) player.y = 20;
    if (player.x > room_width-20) player.x = room_width-20;
    if (player.y > room_height-20) player.y = room_height-20;

    if (player.x > view_wview/2) ... ?
    if (player.y > view_hview/2) ... ?
}

Кстати я пытался заставить его работать, чувствует себя совершенно неправильно, и я Дон'т даже знаю, как я пытаюсь его... любые идеи? Что вы думаете о контексте.преобразование-вещь?

Я надеюсь, вы понимаете мое описание и то, что кто-то имеет представление. С уважением

Решение

[Демо](http://jsfiddle.net/gfcarv/QKgHs/) в jsfiddle.net Это демо иллюстрирует использование просмотра в реальном сценарии игр. Используйте клавиши со стрелками для перемещения игрока по комнате. Большой номер генерируется на лету с помощью прямоугольников и результат сохраняется в изображение. Обратите внимание, что игрок всегда в середине, за исключением, когда рядом с границами (как вы желаете).


Теперь я'постараюсь разъяснить основные части кода, по крайней мере, те части, которые более трудно понять, просто глядя на него.


С помощью метода drawImage для рисования больших изображений ПО для просмотра положение

Вариант drawImage метод имеет восемь новых параметров. Мы можем использовать этот метод для среза части исходного изображения и рисовать их на холсте.

функция drawImage(изображения, ЗХ, сы, sWidth, sHeight, dх, dу, dWidth, dHeight) Первый параметр изображения, как и в других вариантах, либо ссылку на объект, изображение или ссылку на другой элемент canvas. Для остальных восьми параметрам он'лучше посмотрите на изображение ниже. Первые четыре параметра определяют местоположение и размер фрагмента на исходном изображении. Последние четыре параметра определяют положение и размер на целевом холсте. ![Холст метода drawImage][1] Шрифт: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Using_images Как это работает в демо: У нас есть большое изображение, которое представляет номер, и мы хотим показать на холсте только ее часть в пределах области просмотра. Положение растений (ѕх и SY) является одной и той же позиции камеры (технология xview, yView) и размеры урожая такие же, как и в области просмотра(холст) так sWidth=холст.sHeight ширинаи=холст.высота. Мы должны заботиться о размерах урожая, потому что метода drawImage рисует не на холсте, если урожай позиции или размеры сельскохозяйственных культур на основе положения являются недействительными. Что's, почему нам нужен если разделы ниже.

var sx, sy, dx, dy;
var sWidth, sHeight, dWidth, dHeight;

// offset point to crop the image
sx = xView;
sy = yView;

// dimensions of cropped image          
sWidth =  context.canvas.width;
sHeight = context.canvas.height;

// if cropped image is smaller than canvas we need to change the source dimensions
if(image.width - sx < sWidth){
    sWidth = image.width - sx;
}
if(image.height - sy < sHeight){
    sHeight = image.height - sy; 
}

// location on canvas to draw the croped image
dx = 0;
dy = 0;
// match destination with source to not scale the image
dWidth = sWidth;
dHeight = sHeight;          

// draw the cropped image
context.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

Рисование игровых объектов, относящихся к области просмотра

При написании игры это'ы хорошая практика разделения логики и отображения для каждого объекта в игре. Так что в демке мы обновить и функции ничья. "Обновить" изменения метода объекта статус как позицию о "Мир" и, применять законы физики, государственный анимации и т. д. "Рисовать" способ на самом деле сделать объект, а сделать его правильно с учетом просмотра, объект, нужно знать контекст рендеринга и свойства просмотра. Обратите внимание, что объекты игры обновляются с учетом игры World's позиции. Это означает, что (Х,Y) позиции объекта в позицию в мире. Несмотря на это, после просмотра меняется, объекты должны быть оказанными надлежащим образом и позиция визуализации будет отличаться от мира's позиции. Преобразование простой: позиция объекта в мире(номер): (Х, Y)<БР> позиция просмотра:(технология xview, yView) **визуализация позиция**: (х-технология xview, г-yView) Это работает для всех видов координат, даже отрицательных.


Камера Игры

Наши игровые объекты обладают раздельный способ обновления. В реализации демо, камера рассматривается как объект игры, а также имеют раздельный способ обновления. Фотоаппарат объект, удерживая левую верхнюю позицию области просмотра (технология xview, yView), объект для подражания, прямоугольник, представляющий просмотра, прямоугольник, представляющий игре World's границы и минимальное расстояние от каждой границы, что игрок мог быть перед камерой начинается движение (xDeadZone, yDeadZone). Также мы определили камеры'ы степени свободы (оси). На вид сверху, стиль игры, как РПГ, камера может перемещаться по оси X(горизонтальная) и y(вертикальной) оси. Чтобы держать игрока в середине просмотра мы устанавливаем DeadZone на каждой оси сходятся с центром холста. Рассмотрим функцию следовать в коде:

В камеры.следовать(плеер, холст.ширина/2, холст.высота/2) Примечание см. раздел Обновление ниже, так как это не принесет ожидаемого поведения, когда какой-либо из размеров карте (номер) меньше, чем холст.


Мир's в пределах

Поскольку каждый объект, в том числе камеры, имеют собственную функцию обновления, его легко проверить в игре World'границы С. Помните только, чтобы поместить код, который блокирует движение на заключительном функции обновления.


Демонстрация

Увидеть полный код и попробовать его самостоятельно. Большинство части кода имеют комментарии, которые проведут вас через. Я'МР предположить, что вы знакомы с основами JavaScript и как работать с прототипами (иногда я использую термин "Класс" и для прототипа объекта просто потому, что имеют сходное поведение класса в языках, как Java). [Демо](http://jsfiddle.net/gfcarv/QKgHs/) Полный код:






<script>
// wrapper for our game "classes", "methods" and "objects"
window.Game = {};

// wrapper for "class" Rectangle
(function() {
  function Rectangle(left, top, width, height) {
    this.left = left || 0;
    this.top = top || 0;
    this.width = width || 0;
    this.height = height || 0;
    this.right = this.left + this.width;
    this.bottom = this.top + this.height;
  }

  Rectangle.prototype.set = function(left, top, /*optional*/ width, /*optional*/ height) {
    this.left = left;
    this.top = top;
    this.width = width || this.width;
    this.height = height || this.height
    this.right = (this.left + this.width);
    this.bottom = (this.top + this.height);
  }

  Rectangle.prototype.within = function(r) {
    return (r.left = this.right &&
      r.top = this.bottom);
  }

  Rectangle.prototype.overlaps = function(r) {
    return (this.left < r.right &&
      r.left < this.right &&
      this.top < r.bottom &&
      r.top < this.bottom);
  }

  // add "class" Rectangle to our Game object
  Game.Rectangle = Rectangle;
})();

// wrapper for "class" Camera (avoid global objects)
(function() {

  // possibles axis to move the camera
  var AXIS = {
    NONE: 1,
    HORIZONTAL: 2,
    VERTICAL: 3,
    BOTH: 4
  };

  // Camera constructor
  function Camera(xView, yView, viewportWidth, viewportHeight, worldWidth, worldHeight) {
    // position of camera (left-top coordinate)
    this.xView = xView || 0;
    this.yView = yView || 0;

    // distance from followed object to border before camera starts move
    this.xDeadZone = 0; // min distance to horizontal borders
    this.yDeadZone = 0; // min distance to vertical borders

    // viewport dimensions
    this.wView = viewportWidth;
    this.hView = viewportHeight;

    // allow camera to move in vertical and horizontal axis
    this.axis = AXIS.BOTH;

    // object that should be followed
    this.followed = null;

    // rectangle that represents the viewport
    this.viewportRect = new Game.Rectangle(this.xView, this.yView, this.wView, this.hView);

    // rectangle that represents the world's boundary (room's boundary)
    this.worldRect = new Game.Rectangle(0, 0, worldWidth, worldHeight);

  }

  // gameObject needs to have "x" and "y" properties (as world(or room) position)
  Camera.prototype.follow = function(gameObject, xDeadZone, yDeadZone) {
    this.followed = gameObject;
    this.xDeadZone = xDeadZone;
    this.yDeadZone = yDeadZone;
  }

  Camera.prototype.update = function() {
    // keep following the player (or other desired object)
    if (this.followed != null) {
      if (this.axis == AXIS.HORIZONTAL || this.axis == AXIS.BOTH) {
        // moves camera on horizontal axis based on followed object position
        if (this.followed.x - this.xView + this.xDeadZone > this.wView)
          this.xView = this.followed.x - (this.wView - this.xDeadZone);
        else if (this.followed.x - this.xDeadZone < this.xView)
          this.xView = this.followed.x - this.xDeadZone;

      }
      if (this.axis == AXIS.VERTICAL || this.axis == AXIS.BOTH) {
        // moves camera on vertical axis based on followed object position
        if (this.followed.y - this.yView + this.yDeadZone > this.hView)
          this.yView = this.followed.y - (this.hView - this.yDeadZone);
        else if (this.followed.y - this.yDeadZone < this.yView)
          this.yView = this.followed.y - this.yDeadZone;
      }

    }

    // update viewportRect
    this.viewportRect.set(this.xView, this.yView);

    // don't let camera leaves the world's boundary
    if (!this.viewportRect.within(this.worldRect)) {
      if (this.viewportRect.left < this.worldRect.left)
        this.xView = this.worldRect.left;
      if (this.viewportRect.top < this.worldRect.top)
        this.yView = this.worldRect.top;
      if (this.viewportRect.right > this.worldRect.right)
        this.xView = this.worldRect.right - this.wView;
      if (this.viewportRect.bottom > this.worldRect.bottom)
        this.yView = this.worldRect.bottom - this.hView;
    }

  }

  // add "class" Camera to our Game object
  Game.Camera = Camera;

})();

// wrapper for "class" Player
(function() {
  function Player(x, y) {
    // (x, y) = center of object
    // ATTENTION:
    // it represents the player position on the world(room), not the canvas position
    this.x = x;
    this.y = y;

    // move speed in pixels per second
    this.speed = 200;

    // render properties
    this.width = 50;
    this.height = 50;
  }

  Player.prototype.update = function(step, worldWidth, worldHeight) {
    // parameter step is the time between frames ( in seconds )

    // check controls and move the player accordingly
    if (Game.controls.left)
      this.x -= this.speed * step;
    if (Game.controls.up)
      this.y -= this.speed * step;
    if (Game.controls.right)
      this.x += this.speed * step;
    if (Game.controls.down)
      this.y += this.speed * step;

    // don't let player leaves the world's boundary
    if (this.x - this.width / 2 < 0) {
      this.x = this.width / 2;
    }
    if (this.y - this.height / 2 < 0) {
      this.y = this.height / 2;
    }
    if (this.x + this.width / 2 > worldWidth) {
      this.x = worldWidth - this.width / 2;
    }
    if (this.y + this.height / 2 > worldHeight) {
      this.y = worldHeight - this.height / 2;
    }
  }

  Player.prototype.draw = function(context, xView, yView) {
    // draw a simple rectangle shape as our player model
    context.save();
    context.fillStyle = "black";
    // before draw we need to convert player world's position to canvas position            
    context.fillRect((this.x - this.width / 2) - xView, (this.y - this.height / 2) - yView, this.width, this.height);
    context.restore();
  }

  // add "class" Player to our Game object
  Game.Player = Player;

})();

// wrapper for "class" Map
(function() {
  function Map(width, height) {
    // map dimensions
    this.width = width;
    this.height = height;

    // map texture
    this.image = null;
  }

  // creates a prodedural generated map (you can use an image instead)
  Map.prototype.generate = function() {
    var ctx = document.createElement("canvas").getContext("2d");
    ctx.canvas.width = this.width;
    ctx.canvas.height = this.height;

    var rows = ~~(this.width / 44) + 1;
    var columns = ~~(this.height / 44) + 1;

    var color = "red";
    ctx.save();
    ctx.fillStyle = "red";
    for (var x = 0, i = 0; i < rows; x += 44, i++) {
      ctx.beginPath();
      for (var y = 0, j = 0; j < columns; y += 44, j++) {
        ctx.rect(x, y, 40, 40);
      }
      color = (color == "red" ? "blue" : "red");
      ctx.fillStyle = color;
      ctx.fill();
      ctx.closePath();
    }
    ctx.restore();

    // store the generate map as this image texture
    this.image = new Image();
    this.image.src = ctx.canvas.toDataURL("image/png");

    // clear context
    ctx = null;
  }

  // draw the map adjusted to camera
  Map.prototype.draw = function(context, xView, yView) {
    // easiest way: draw the entire map changing only the destination coordinate in canvas
    // canvas will cull the image by itself (no performance gaps -> in hardware accelerated environments, at least)
    /*context.drawImage(this.image, 0, 0, this.image.width, this.image.height, -xView, -yView, this.image.width, this.image.height);*/

    // didactic way ( "s" is for "source" and "d" is for "destination" in the variable names):

    var sx, sy, dx, dy;
    var sWidth, sHeight, dWidth, dHeight;

    // offset point to crop the image
    sx = xView;
    sy = yView;

    // dimensions of cropped image          
    sWidth = context.canvas.width;
    sHeight = context.canvas.height;

    // if cropped image is smaller than canvas we need to change the source dimensions
    if (this.image.width - sx < sWidth) {
      sWidth = this.image.width - sx;
    }
    if (this.image.height - sy < sHeight) {
      sHeight = this.image.height - sy;
    }

    // location on canvas to draw the croped image
    dx = 0;
    dy = 0;
    // match destination with source to not scale the image
    dWidth = sWidth;
    dHeight = sHeight;

    context.drawImage(this.image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
  }

  // add "class" Map to our Game object
  Game.Map = Map;

})();

// Game Script
(function() {
  // prepaire our game canvas
  var canvas = document.getElementById("gameCanvas");
  var context = canvas.getContext("2d");

  // game settings: 
  var FPS = 30;
  var INTERVAL = 1000 / FPS; // milliseconds
  var STEP = INTERVAL / 1000 // seconds

  // setup an object that represents the room
  var room = {
    width: 500,
    height: 300,
    map: new Game.Map(500, 300)
  };

  // generate a large image texture for the room
  room.map.generate();

  // setup player
  var player = new Game.Player(50, 50);

  // Old camera setup. It not works with maps smaller than canvas. Keeping the code deactivated here as reference.
  /* var camera = new Game.Camera(0, 0, canvas.width, canvas.height, room.width, room.height);*/
  /* camera.follow(player, canvas.width / 2, canvas.height / 2); */

  // Set the right viewport size for the camera
  var vWidth = Math.min(room.width, canvas.width);
  var vHeight = Math.min(room.height, canvas.height);

  // Setup the camera
  var camera = new Game.Camera(0, 0, vWidth, vHeight, room.width, room.height);
  camera.follow(player, vWidth / 2, vHeight / 2);

  // Game update function
  var update = function() {
    player.update(STEP, room.width, room.height);
    camera.update();
  }

  // Game draw function
  var draw = function() {
    // clear the entire canvas
    context.clearRect(0, 0, canvas.width, canvas.height);

    // redraw all objects
    room.map.draw(context, camera.xView, camera.yView);
    player.draw(context, camera.xView, camera.yView);
  }

  // Game Loop
  var gameLoop = function() {
    update();
    draw();
  }

  // 
Комментарии (12)

Код в принятый ответ-это многовато. Его это просто:

function draw() {
    ctx.setTransform(1,0,0,1,0,0);//reset the transform matrix as it is cumulative
    ctx.clearRect(0, 0, canvas.width, canvas.height);//clear the viewport AFTER the matrix is reset

    //Clamp the camera position to the world bounds while centering the camera around the player                                             
    var camX = clamp(-player.x + canvas.width/2, yourWorld.minX, yourWorld.maxX - canvas.width);
    var camY = clamp(-player.y + canvas.height/2, yourWorld.minY, yourWorld.maxY - canvas.height);

    ctx.translate( camX, camY );    

    //Draw everything
}

И хомут выглядит так:

function clamp(value, min, max){
    if(value < min) return min;
    else if(value > max) return max;
    return value;
}
Комментарии (7)

Вот как использовать холст для просмотра на другом больше, чем холст изображения

Видовой экран-это просто обрезается часть более крупного изображения, который отображается для пользователя.

В этом случае просмотра будет отображаться пользователю на холсте (холст просмотра).

Во-первых, код функции движение, которое перемещает просмотра вокруг изображения большего размера.

Эта функция перемещает верхний/левый угол просмотра по 5 пикселей в заданном направлении:

function move(direction){
    switch (direction){
        case "left":
            left-=5;
            break;
        case "up":
            top-=5;
            break;
        case "right":
            left+=5;
            break;
        case "down":
            top+=5
            break;
    }
    draw(top,left);
}

Функции перемещения вызывает функцию рисования.

В Draw(), то функция drawImage функция будет обрезать определенную часть общей картинки.

функция drawImage также показывает, что “обрезанные фон” пользователю на холсте.

context.clearRect(0,0,game.width,game.height);
context.drawImage(background,cropLeft,cropTop,cropWidth,cropHeight,
                     0,0,viewWidth,viewHeight);

В этом примере

Фоне полного фоновое изображение (обычно не отображается, но это скорее источник для обрезки)

cropLeft & cropTop определить, где на фоне изображения обрезки начнется.

cropWidth & cropHeight определить, как большой прямоугольник будет обрезана от фона изображения.

0,0 сказать, что суб-изображения, которые были купированы на фоне будет нарисован в 0,0 на окна холст.

viewwidth значение & viewheight значение имеют ширина и высота области просмотра холсте

Так вот пример метода drawImage с помощью чисел.

Скажем, в нашей области просмотра (= наш дисплей холст) составляет 150 пикселов в ширину и 100 пикселей в высоту.

context.drawImage(background,75,50,150,100,0,0,150,100);

На 75 & 50 говорят, что обрезки будут начинаться в позиции x=75/г=50 на фоне изображения.

В 150,100 сказать, что прямоугольник обрезки будет шириной 150 и высотой 100.

В 0,0,150,100 сказать, что обрезанное изображение прямоугольника будет отображаться, используя полный размер просмотра холста.

Вот именно для механики рисунка видового экрана...просто добавить ключ-контроль!

Вот код и скрипку: http://jsfiddle.net/m1erickson/vXqyc/





<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>


    body{ background-color: ivory; }
    canvas{border:1px solid red;}


<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var game=document.getElementById("game");
    var gameCtx=game.getContext("2d");

    var left=20;
    var top=20;

    var background=new Image();
    background.onload=function(){
        canvas.width=background.width/2;
        canvas.height=background.height/2;
        gameCtx.fillStyle="red";
        gameCtx.strokeStyle="blue";
        gameCtx.lineWidth=3;
        ctx.fillStyle="red";
        ctx.strokeStyle="blue";
        ctx.lineWidth=3;
        move(top,left);
    }
    background.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/game.jpg";

    function move(direction){
        switch (direction){
            case "left":
                left-=5;
                break;
            case "up":
                top-=5;
                break;
            case "right":
                left+=5;
                break;
            case "down":
                top+=5
                break;
        }
        draw(top,left);
    }

    function draw(top,left){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.drawImage(background,0,0,background.width,background.height,0,0,canvas.width,canvas.height);
        gameCtx.clearRect(0,0,game.width,game.height);
        gameCtx.drawImage(background,left,top,250,150,0,0,250,150);
        gameCtx.beginPath();
        gameCtx.arc(125,75,10,0,Math.PI*2,false);
        gameCtx.closePath();
        gameCtx.fill();
        gameCtx.stroke();
        ctx.beginPath();
        ctx.rect(left/2,top/2,125,75);
        ctx.stroke();
        ctx.beginPath();
        ctx.arc(left/2+125/2,top/2+75/2,5,0,Math.PI*2,false);
        ctx.stroke();
        ctx.fill();
    }

    $("#moveLeft").click(function(){move("left");}); 
    $("#moveRight").click(function(){move("right");}); 
    $("#moveUp").click(function(){move("up");}); 
    $("#moveDown").click(function(){move("down");}); 

}); // end $(function(){});
</script>




    <br>
    <br>
    Left
    Right
    Up
    Down

Комментарии (2)

Путь вы'ре собираюсь сейчас об этом представляется правильным мне. Я бы поменял на "20" и хотя границы переменной, так что вы можете легко изменить границы уровня или всю игру, если вам требуется так.

Вы могли бы реферат из этой логики, в конкретных-то "просмотра" и способ, что бы просто ручка расчеты, необходимые для определения, где вашу "Камера", которая должна быть на карте, а затем убедитесь, что X и y-координаты персонажа матч в центре камеры.

Вы также можете перевернуть этот метод и определить местоположение вашей камеры исходя из положения персонажей (напр.: (поз.х - (desired_camera_size.ширина / 2))) и сделать камеру от этого.

Когда у вас есть ваша позиция камеры разобрались, можно начать переживать по поводу рисования сам номер в качестве первого слоя холста.

Комментарии (0)

Это просто вопрос настройки просмотра к цели'ы X и y, Колтон государства, на каждом кадре. Преобразования не нужны, но могут быть использованы в качестве желаемой. Формула, что работал для меня было:

function update() {

  // Assign the viewport to follow a target for this frame
  viewport.x = -target.x + canvas.width / 2;
  viewport.y = -target.y + canvas.height / 2;

  // Draw each entity, including the target, relative to the viewport
  ctx.fillRect(
    entity.x + viewport.x, 
    entity.y + viewport.y,
    entity.size,
    entity.size
  );
}

Зажимая на карту-это необязательный второй шаг:

function update() {

  // Assign the viewport to follow a target for this frame
  viewport.x = -target.x + canvas.width / 2;
  viewport.y = -target.y + canvas.height / 2;

  // Keep viewport in map bounds
  viewport.x = clamp(viewport.x, canvas.width - map.width, 0);
  viewport.y = clamp(viewport.y, canvas.height - map.height, 0);

  // Draw each entity, including the target, relative to the viewport
  ctx.fillRect(
    entity.x + viewport.x, 
    entity.y + viewport.y,
    entity.size,
    entity.size
  );
}

// Restrict n to a range between lo and hi
const clamp = (n, lo, hi) => n < lo ? lo : n > hi ? hi : n;

Здесь'ы пример: https://jsfiddle.net/ggorlen/7yv7u572/

Комментарии (0)

@Густаво Карвальо'ы решение является феноменальным, но это связано с большим объемом вычислений и познавательную нагрузку. @Колтон'ы подход является шагом в правильном направлении, жаль, что это была'т выработано достаточно в его ответ. Я взял его идею и побежал с ним, чтобы создать этот сайт CodePen. Он достигает именно то, что @user2337969 просит за использование контекста.перевод. Красота заключается в том, что это не&#39;т требует взаимозачет любую карту или игрока координаты, чтобы рисовать их так же легко, как с помощью ихXиy` напрямую, что гораздо проще.

Думать о 2D камеры в виде прямоугольника, внутри кастрюли карте большего размера. Его верхний левый угол в(Х, Y) координаты на карте, и его размер-это полотно, т. е. полотно.ширинаихолст.высота. Это означает, что " Х " может находиться в диапазоне от0докарте.ширина - холст.ширина, иyот0докарте.высота - холст.высота(включительно). Эти отметке " min " и "Max", которыми нас кормят в @Колтон&#39;s методхомут`.

Чтобы сделать его работу, мне пришлось перевернуть знак на X и Y с context.translateположительные значения сдвигают холст вправо (создавая иллюзию, как будто не хватало), а отрицательные - влево (как бы радио).

Комментарии (0)