Как сделать так, чтобы «Камера» показывала только часть загруженной области - PullRequest
5 голосов
/ 14 октября 2011

У меня небольшая проблема с выяснением чего-либо (очевидно).

Я создаю 2D Top-down mmorpg, и в этой игре я хочу, чтобы игрок перемещался по плиточной карте, аналогично тому, как работала игра Pokemon, если кто-нибудь когда-либо играл в нее.

Если у вас нет, представьте себе следующее: мне нужно загрузить различные области, создавая их из плиток, которые содержат изображение и местоположение (x, y) и объекты (игроки, предметы), но игрок может видеть толькочасть этого за один раз, а именно область размером 20 на 15 плиток, которая может составлять 100 сек плиток высотой / шириной.Я хочу, чтобы «камера» следовала за игроком, удерживая его в центре, если игрок не достигнет края загруженной области.

Мне не обязательно код, просто план проекта.Я понятия не имею, как поступить с такими вещами.

Я думал о возможном разделении всей загруженной области на фрагменты плитки размером 10x10, называемые «блоками», и их загрузке, но я все еще не уверен, как загружать фрагменты за пределы экрана и показывать их только тогда, когда игрокнаходится в пределах досягаемости.

Картинка должна описать это: enter image description here

Есть идеи?


Мое решение: Я решил эту проблему благодаря чудесному миру JScrollPanes и JPanels.

Iдобавили блок JPanels 3x3 внутри JScrollPane, добавили пару методов прокрутки и "goto" для центрирования / перемещения JScrollPane, и вуаля, у меня была камера.

В то время какОтвет, который я выбрал, был немного более общим для людей, желающих делать 2d-камеру, то, как я это сделал, на самом деле помогло мне визуализировать, что я делаю, немного лучше, так как у меня фактически была физическая «Камера» (JScrollPane), чтобы перемещаться по моей ».Мир "(3x3 Grid of JPanels)

Просто подумал, что я опубликую это здесь, на случай, если кто-нибудь будет искать ответ, и это пришло в голову.:)

Ответы [ 3 ]

5 голосов
/ 15 октября 2011

В 2D-игре довольно легко определить, какие плитки попадают в прямоугольник вида, если плитки прямоугольные. По сути, изобразите прямоугольник «области просмотра» внутри большего прямоугольника мира. Разделив смещения вида на размеры плитки, вы можете легко определить начальную плитку, а затем просто отобразить плитки в том виде, в котором они находятся внутри вида.

Во-первых, вы работаете в трех системах координат: вид, мир и карта. Координаты вида - это, по сути, смещения мыши от верхнего левого угла вида. Мировые координаты - это расстояния в пикселях от левого верхнего угла фрагмента 0, 0. Я предполагаю, что ваш мир начинается в верхнем левом углу. И координаты карты - это x, y индексы в массиве карты.

Вам нужно будет выполнить конвертацию между ними, чтобы сделать «причудливые» вещи, такие как прокрутка, выяснение того, какая плитка находится под мышью, и рисование объектов мира с правильными координатами на виде. Итак, вам понадобятся некоторые функции для преобразования между этими системами:

// I haven't touched Java in years, but JavaScript should be easy enough to convey the point

var TileWidth = 40,
    TileHeight = 40;

function View() {
    this.viewOrigin = [0, 0];   // scroll offset
    this.viewSize = [600, 400];
    this.map = null;
    this.worldSize = [0, 0];
}

View.prototype.viewToWorld = function(v, w) {
    w[0] = v[0] + this.viewOrigin[0];
    w[1] = v[1] + this.viewOrigin[1];
};

View.prototype.worldToMap = function(w, m) {
    m[0] = Math.floor(w[0] / TileWidth);
    m[1] = Math.floor(w[1] / TileHeight);
}

View.prototype.mapToWorld = function(m, w) {
    w[0] = m[0] * TileWidth;
    w[1] = m[1] * TileHeight;
};

View.prototype.worldToView = function(w, v) {
    v[0] = w[0] - this.viewOrigin[0];
    v[1] = w[1] - this.viewOrigin[1];
}

Вооружившись этими функциями, мы теперь можем визуализировать видимую часть карты ...

View.prototype.draw = function() {
    var mapStartPos = [0, 0],
    worldStartPos = [0, 0],
    viewStartPos = [0, 0];
    mx, my, // map coordinates of current tile
    vx, vy; // view coordinates of current tile

    this.worldToMap(this.viewOrigin, mapStartPos); // which tile is closest to the view origin?
    this.mapToWorld(mapStartPos, worldStartPos);    // round world position to tile corner...
    this.worldToView(worldStartPos, viewStartPos);  // ... and then convert to view coordinates. this allows per-pixel scrolling

    mx = mapStartPos[0];
    my = mapStartPos[y];

    for (vy = viewStartPos[1]; vy < this.viewSize[1]; vy += TileHeight) {
        for (vx = viewStartPos[0]; vx < this.viewSize[0]; vy += TileWidth) {
            var tile = this.map.get(mx++, my);
            this.drawTile(tile, vx, vy);
        }
        mx = mapStartPos[0];
        my++;
        vy += TileHeight;
    }
};

Это должно сработать. У меня не было времени собрать рабочую демонстрационную веб-страницу, но я надеюсь, что вы поняли идею. Изменяя viewOrigin, вы можете прокручивать. Чтобы получить мир и отобразить координаты под мышью, используйте функции viewToWorld и worldToMap.

Если вы планируете изометрический вид, т. Е. Diablo, то все становится намного сложнее.

Удачи!

1 голос
/ 15 октября 2011

Я бы так и сделал, сохранив переменную с именем cameraPosition или что-то в этом роде.Затем, в методе draw всех объектов, используйте cameraPosition для смещения местоположения всего.

Например: камень находится в [100,50], а камера в [75,75].Это означает, что камень должен быть нарисован в [25,-25] (результат [100,50] - [75,75]).

Возможно, вам придется немного подправить это, чтобы заставить его работать (например, возможно, вам придется компенсировать размер окна),Обратите внимание, что вы также должны сделать небольшую выборку - если что-то хочет нарисовать в [2460,-830], вы, вероятно, не хотите беспокоиться о рисовании.

0 голосов
/ 14 октября 2011

Один из подходов заключается в использовании двойной буферизации ( Java Double Buffering ) и блиттинга (http://download.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html).С ним даже связан шаблон дизайна (http://www.javalobby.org/forums/thread.jspa?threadID=16867&tstart=0).

...