【问题标题】:How to have a "Camera" only show a portion of a loaded area如何让“相机”只显示加载区域的一部分
【发布时间】:2011-10-14 19:24:46
【问题描述】:

我在弄清楚一些事情时遇到了一点问题(显然)。

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

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

我不一定需要代码,只需要一个设计计划。我不知道如何去做这种事情。

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

图片应该描述它:

有什么想法吗?


我的解决方案: 我解决这个问题的方法是通过 JScrollPanes 和 JPanels 的奇妙世界。

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

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

只是想我会在这里发布这个,以防有人在谷歌上搜索答案并且这个出现了。 :)

【问题讨论】:

  • 这个问题对您来说可能看起来很复杂,因为您正在处理二维; x 和 y。您应该获得一些游戏开发经验来解决更简单的问题,例如一个横向滚动平台游戏,只需要您考虑 x 的问题,而忽略 y。当我以业余爱好开始游戏开发时,我制作了一些静态视图游戏,例如乒乓球和太空入侵者,并通过平台游戏转向了 2D 横向滚动。我的下一个项目将类似于您在水平和垂直运动中所做的事情,我希望在那之后我可以将头绕在 3D 周围。祝你好运!
  • 要考虑的另一件事:您说黑色是“加载区域”。在 Pokemon、Zelda 和所有其他使用这种相机风格的游戏中,您无法将角色移动到屏幕上尚未出现的位置。这意味着您没有“加载”整个区域,只有玩家可以看到的部分。做出这个决定会产生后果,如果你只加载你正在绘制的区域,玩家可以走开然后走回来,也许一些以前不存在的随机项目会出现,然后如果他们再次走开并返回,就会消失.思考问题的两种方式..
  • 我发现了我的问题。我决定收集一组图块,并将从服务器传递的字符串数组和当前图块集合中的每个地图拼凑在一起。摄像头始终以播放器为中心,效果非常好。

标签: java swing 2d paint


【解决方案1】:

对于 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 函数。

如果您计划使用等轴测视图,即暗黑破坏神,那么事情会变得相当棘手。

祝你好运!

【讨论】:

    【解决方案2】:

    我会做这样的事情的方式是保留一个名为cameraPosition 的变量或其他东西。然后,在所有对象的draw方法中,使用cameraPosition来偏移所有对象的位置。

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

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

    【讨论】:

    • 这有点像我的想法,但是我如何将这个大“图像”加载到内存中?
    • 刚刚写了最后一条评论,您认为是否有可能只存储大量这些“瓷砖”,并且只在看到的每一块瓷砖上涂漆?也许在一个数组中?我觉得这样不会节省内存,因为我必须检查玩家计划移动到的每个数组,以确保玩家或对象不在那里,并且它不是被阻塞的图块
    【解决方案3】:

    【讨论】:

    • 我不确定我是否理解。你说我应该在屏幕视野之外“缓冲”我的图像,然后随着玩家的前进将其移入?如果玩家离开,我将如何将其移回“缓冲”阶段?
    猜你喜欢
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多