Итак, я делаю HTML5 RPG просто для удовольствия. Карта представляет собой <canvas>
(ширина 512 пикселей, высота 352 пикселя | 16 плиток в поперечнике, 11 плиток сверху вниз). Я хочу знать, есть ли более эффективный способ рисовать <canvas>
.
Вот как у меня это сейчас.
Как плитки загружены и нарисованы на карте
Карта рисуется плиткой (32х32) с использованием Image()
фигуры. Файлы изображений загружаются через простой for
цикл и помещаются в массив, вызываемый tiles[]
для использования при рисовании drawImage()
.
Сначала мы загружаем плитки ...
и вот как это делается:
// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "js/tiles/t" + x + ".png";
imageObj.onload = function () {
console.log("Added tile ... " + loadedImagesCount);
loadedImagesCount++;
if (loadedImagesCount == NUM_OF_TILES) {
// Onces all tiles are loaded ...
// We paint the map
for (y = 0; y <= 15; y++) {
for (x = 0; x <= 10; x++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[5], theY, theX, 32, 32);
}
}
}
};
tiles.push(imageObj);
}
Естественно, когда игрок начинает игру, он загружает карту, которую он в последний раз остановил. Но здесь, это карта всех трав.
Прямо сейчас, карты используют 2D-массивы. Вот пример карты.
[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1],
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];
Я получаю разные карты, используя простую if
структуру. Как только 2d массив выше return
, соответствующий номер в каждом массиве будет окрашен в соответствии с Image()
сохраненным внутри tile[]
. Затем drawImage()
произойдет и закрасить в соответствии с x
и y
и раз его, 32
чтобы закрасить по правильной x-y
координате.
Как происходит многократное переключение карт
С моей игры, карты есть пять вещей , чтобы следить за: currentID
, leftID
, rightID
, upID
, и bottomID
.
- currentID: текущий идентификатор карты, на которой вы находитесь.
- leftID: какой идентификатор
currentID
загружать при выходе слева от текущей карты. - rightID: какой идентификатор
currentID
загружать при выходе справа от текущей карты. - downID: какой идентификатор
currentID
загружать при выходе из нижней части текущей карты. - upID: какой идентификатор
currentID
загружать при выходе из верхней части текущей карты.
Что - то Примечание: Если какая- либо leftID
, rightID
, upID
или bottomID
не являются специфичными, это означает , что они являются 0
. Это означает, что они не могут покинуть эту сторону карты. Это просто невидимая блокада.
Таким образом, как только человек выходит из стороны карты, в зависимости от того, где он вышел ... например, если он вышел из нижней части, bottomID
будет номер map
загрузки и, таким образом, будет отображаться на карте.
Вот представительный .GIF, чтобы помочь вам лучше визуализировать:
Как вы можете видеть, рано или поздно со многими картами я буду иметь дело со многими идентификаторами. И это может стать немного запутанным и беспокойным.
Очевидным плюсом является то, что он загружает 176 плиток за раз, обновляет небольшой холст 512x352 и обрабатывает одну карту за раз. Дело в том, что идентификаторы MAP при работе со многими картами могут иногда сбивать с толку.
Мой вопрос
- Это эффективный способ хранения карт (с учетом использования листов) или есть лучший способ обработки карт?
Я думал по линии гигантской карты. Размер карты большой, и все это один массив 2D. Однако область просмотра по-прежнему составляет 512x352 пикселей.
Вот еще один .gif, который я сделал (для этого вопроса), чтобы помочь визуализировать:
Извините, если вы не понимаете мой английский. Пожалуйста, спросите все, что у вас есть проблемы с пониманием. Надеюсь, я дал понять. Благодарю.
источник
Ответы:
Изменить: только что увидел, что мой ответ был основан на вашем коде, но на самом деле не ответил на ваш вопрос. Я сохранил старый ответ на случай, если вы сможете использовать эту информацию.
Редактировать 2: я исправил 2 проблемы с исходным кодом: - добавление +1 в вычислении конца x и y было ошибочно заключено в скобки, но его нужно добавить после деления. - Я забыл проверить значения х и у.
Вы можете просто сохранить текущую карту в памяти и загрузить окружающие карты. Представьте себе мир, который состоит из двумерного массива одиночных уровней размером 5х5. Игрок начинает с поля 1. Поскольку верхняя и левая границы уровня находятся на краю мира, их не нужно загружать. Таким образом, в этом случае уровень 1/1 активен, а уровни 1/2 и 2/1 загружены ... Если игрок теперь перемещается вправо, все уровни (кроме того, на который вы переходите) выгружаются, и новое окружение загружен. Значит, уровень 2/1 теперь активен, 1/1, 2/2 и 3/1 теперь загружены.
Я надеюсь, что это дает вам представление о том, как это можно сделать. Но этот подход не будет работать очень хорошо, когда каждый уровень должен быть симулирован во время игры. Но если вы можете заморозить неиспользуемые уровни, это должно работать нормально.
Старый ответ:
То, что я делаю при рендеринге уровня (также на основе плиток), это чтобы вычислить, какие элементы из массива плиток пересекаются с окном просмотра, и тогда я только визуализирую эти плитки. Например, у вас могут быть большие карты, но вам нужно только отобразить часть на экране.
Примечание: приведенный выше код не тестируется, но он должен дать представление о том, что делать.
Следуя базовому примеру представления представления:
Представление javascript будет выглядеть
Если вы возьмете мой пример кода, вам просто придется заменить объявления int и float на var. Также убедитесь, что вы используете Math.floor в тех вычислениях, которые присваиваются значениям на основе int, чтобы получить то же поведение.
Одна вещь, которую я хотел бы рассмотреть (хотя я не уверен, имеет ли это значение в javascript), - это поместить все плитки (или как можно больше) в одну большую текстуру вместо использования множества отдельных файлов.
Вот ссылка, объясняющая, как это сделать: http://thiscouldbebetter.wordpress.com/2012/02/25/slicing-an-image-into-tiles-in-javascript/
источник
640, 480
.. но это может работать с512, 352
правильно?Хранение карт в виде плиток полезно для повторного использования ресурсов и повторного проектирования карты. Реально, хотя это не дает большой пользы для игрока. Кроме того, вы каждый раз перерисовываете каждый тайл. Вот что я бы сделал:
Храните всю карту как один большой массив. Нет смысла иметь карты и субкарты, а также потенциально субкарты (например, если вы входите в здания). Вы загружаете все это так или иначе, и это делает все простым и понятным.
Визуализируйте карту сразу. Имейте внеэкранный холст, на который вы рендерите карту, а затем используйте это в своей игре. На этой странице показано, как это сделать с помощью простой функции JavaScript:
Это при условии, что ваша карта не изменится сильно. Если вы хотите отобразить субкарты на месте (например, внутри здания), вы просто отрендерите это и на холст, а затем нарисуете его сверху. Вот пример того, как вы можете использовать это для рендеринга вашей карты:
Это нарисует небольшую часть карты вокруг
mapCentreX, mapCentreY
. Это предложит вам плавную прокрутку по всей карте, а также перемещение суб-плитки - вы можете сохранить положение игрока как 1/32 от плитки, чтобы вы могли плавно перемещаться по карте (ясно, если вы хотите Перемещение плитки за плиткой в качестве стилистического выбора, вы можете просто увеличить куски 32).Вы по-прежнему можете разделить карту на части, если хотите, или если ваш мир огромен и не помещается в памяти ваших целевых систем (имейте в виду, что даже для 1 байта на пиксель карта 512x352 составляет 176 КБ), но предварительно - при рендеринге вашей карты вы увидите значительное увеличение производительности в большинстве браузеров.
Это дает вам гибкость повторного использования плиток по всему миру без головной боли при редактировании одного большого изображения, а также позволяет быстро и легко запускать это и рассматривать только одну «карту» (или столько «карт», сколько вам нужно) ,
источник
Во всех реализациях, которые я видел, карты тайлов часто генерируются как одно большое изображение, а затем «разбиваются» на более мелкие части.
https://gamedev.stackexchange.com/a/25035/10055
Эти куски обычно имеют степень 2, поэтому они оптимально вписываются в память.
источник
Простой способ отследить идентификаторы - просто использовать другой 2d-массив с ними: поддерживая только x, y в этом «мета-массиве», вы можете легко искать другие идентификаторы.
Это , как говорится, вот взять Google на 2D плиточный холст игр (ну, на самом деле HTML5 мультиплеер, но плитка двигатель также охватывается) от недавней I / O 2012: http://www.youtube.com/watch?v=Prkyd5n0P7k It также имеет доступный исходный код.
источник
Ваша идея сначала загрузить всю карту в массив - это эффективный способ, но получить JavaScript Injection'd будет легко, любой сможет узнать карту и отправится в приключение.
Я также работаю над RPG-игрой, основанной на веб-технологиях. Я загружаю свою карту с помощью Ajax со страницы PHP, которая загружает карту из базы данных, где указано X, Y, Z-положение и vlaue. из плитки, нарисуйте его, и, наконец, игрок двигаться.
Я все еще работаю над этим, чтобы сделать его более эффективным, но карта загружается достаточно быстро, чтобы сохранить его таким.
источник
Нет , массив является наиболее эффективным способом хранения карты тайлов .
Может быть несколько структур, которые требуют немного меньше памяти, но только за счет гораздо более высоких затрат на загрузку и доступ к данным.
Однако нужно немного подумать, когда вы собираетесь загрузить следующую карту. Учитывая, что карты не особенно большие, то, что на самом деле займет больше всего времени, ждет сервер, чтобы доставить карту. Фактическая загрузка займет всего несколько миллисекунд. Но это ожидание может быть асинхронным, оно не должно блокировать ход игры. Так что лучше всего загружать данные не по мере необходимости, а раньше. Игрок находится на одной карте, теперь загружаются все соседние карты. Игрок перемещается на следующую карту, снова загружает все смежные карты и т. Д. И т. П. Игрок даже не заметит, что ваша игра загружается в фоновом режиме.
Таким образом, вы также можете создать иллюзию мира без границ, также рисуя смежные карты, в этом случае вам нужно загрузить не только соседние карты, но и те, которые примыкают к ним.
источник
Я не уверен, почему вы думаете: как вы видите, рано или поздно со многими картами я буду иметь дело со многими удостоверениями личности. И это может стать немного запутанным и беспокойным.
LeftID всегда будет -1 от currentID, rightID всегда будет +1 от currentID.
UpID всегда будет - (общая ширина карты) текущего идентификатора, а downID всегда будет + (общая ширина карты) текущего идентификатора, за исключением нуля, означающего, что вы достигли края.
Одна карта может быть разбита на несколько карт и последовательно сохранена с mapIDXXXX, где XXXX - идентификатор. Таким образом, не надо ничего путать. Я был на вашем сайте, и, кажется, я могу ошибаться, что проблема заключается в том, что ваш редактор карт устанавливает ограничение по размеру, которое мешает вашей автоматизации разбивать большую карту на несколько маленьких при сохранении, и это ограничение возможно ограничивающее техническое решение.
Я написал редактор карт Javascript, который прокручивает плитки во всех направлениях, 1000 x 1000 (я бы не рекомендовал этот размер), и он все еще перемещается так же хорошо, как карта 50 x 50, и это с 3 слоями, включая прокрутку параллакса. Сохраняет и читает в формате JSON. Я пришлю вам копию, если вы скажете, что не возражаете против электронного письма, приблизительно 2 мг. Он предназначен для работы на github, но у меня нет приличного (легального) набора плиток, поэтому я пока не удосужился поставить его там.
источник