如何让“相机”仅显示加载区域的一部分

时间:2011-10-14 19:24:46

标签: java swing 2d paint

我遇到一些问题(显然)。

我正在创建一个2D自上而下的mmorpg,在这个游戏中我希望玩家能够在一个平铺的地图上移动,类似于游戏Pokemon的工作方式,如果有人玩过它的话。

如果还没有,请想象一下:我需要加载各个区域,从包含图像和位置(x,y)和对象(玩家,项目)的图块构建它们但玩家只能看到一部分它一次,即一个20乘15的瓷砖区域,可以是100个高/宽的瓷砖。我希望“相机”跟随玩家,让他保持在中心,除非玩家到达加载区域的边缘。

我不需要代码,只需要一个设计方案。我不知道怎么去做这种事情。

我在考虑将整个加载区域分成10x10块,称为“块”并加载它们,但我仍然不确定如何在屏幕上加载碎片并仅在玩家在范围内时显示它们

图片应描述: enter image description here

有什么想法吗?


我的解决方案: 我解决这个问题的方式是通过JScrollPanes和JPanels的精彩世界。

我在JScrollPane中添加了一个3x3的JPanel块,添加了几个滚动和“goto”方法来集中/移动JScrollPane,瞧,我有我的相机。

虽然我选择的答案对于想要做2d相机的人来说更通用一点,我这样做的方式实际上帮助我想象我做得更好一点,因为我实际上有一个物理“相机” (JScrollPane)移动我的“世界”(3x3网格JPanels)

我以为我会在这里发帖,以防有人在谷歌上搜索答案,这就出现了。 :)

3 个答案:

答案 0 :(得分:4)

对于2D游戏,如果瓷砖是矩形的,很容易弄清楚哪些瓷砖属于视图矩形。基本上,在较大的世界矩形内部绘制一个“视口”矩形。通过将视图偏移除以图块大小,您可以轻松确定起始图块,然后只需在视图内渲染适合的图块。

首先,您正在使用三个坐标系:视图,世界和地图。视图坐标基本上是视图左上角的鼠标偏移。世界坐标是距离图块0的左上角的像素距离。我假设您的世界从左上角开始。并且映射cooridnates是映射数组中的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函数。

如果你正在计划一个等距视图,即暗黑破坏神,那么事情变得相当棘手。

祝你好运!

答案 1 :(得分:1)

我这样做的方法是保留一个名为cameraPosition的变量。然后,在所有对象的draw方法中,使用cameraPosition来偏移所有对象的位置。

例如:摇滚在[100,50],而相机在[75,75]。这意味着应该在[25,-25]处绘制岩石([100,50] - [75,75]的结果)。

您可能需要稍微调整一下才能使其正常工作(例如,您可能需要补偿窗口大小)。请注意,您还应该进行一些剔除 - 如果想要在[2460,-830]绘制某些内容,您可能不想费心去绘制它。

答案 2 :(得分:0)