【问题标题】:libGDX: How to handle collisions for sprites from the Tiled object layer?libGDX:如何处理平铺对象层中精灵的碰撞?
【发布时间】:2013-04-22 00:42:52
【问题描述】:

我正在使用 libGDXTiled 来制作 RPG。我已经有很多东西在工作:标题屏幕,一个测试屏幕,上面加载了我的地图。我可以读取我放在地图和某些图块上的属性。我也可以在地图上到处移动,但我现在想弄清楚的是:

如何从对象层渲染地图对象并处理碰撞?

我想为我的碰撞层使用 Tiled 的对象层。 IE:在我不希望角色通过的某些图块/区域周围放置形状。

这是我目前所拥有的:

package rawct.awakening;

import java.lang.reflect.Method;
import java.util.Iterator;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileSet;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;

public class GameMap extends TiledMap {
    private String TAG = "GameMap";
    private TmxMapLoader loader = new TmxMapLoader();
    private OrthogonalTiledMapRenderer mRender;

    private TiledMap gamemap;
    private TiledMapTileLayer mapTiles;

    private ObjectMap<TiledMapTile, Boolean> Blocked;
    private ObjectMap<TiledMapTile, Boolean> Event;

    private MapObjects mObjects = new MapObjects();
    private MapObject mObj;

    public void draw(OrthographicCamera cam){
        mRender.setView(cam);
        mRender.render();
    // Should render my map object?
        mRender.renderObject(mObj);
    }

    public GameMap(String Map){
        Blocked = new ObjectMap<TiledMapTile, Boolean>();
        Event = new ObjectMap<TiledMapTile, Boolean>();

        gamemap = loader.load("maps/"+Map+".tmx");
        mRender = new OrthogonalTiledMapRenderer(gamemap);
        loadMap(gamemap);
    }

    private Cell getCellAt(float x, float y){
        return mapTiles.getCell((int)x, (int)y);
    }

    private TiledMapTile getTileAt(float x, float y){
        Cell cell = getCellAt(x, y);
        return cell != null ? cell.getTile() : null;
    }

    public boolean isTileBlocked(float x, float y){
        try {
            return Blocked.get(getTileAt(x, y));
        } catch (Exception e) {
            Gdx.app.log(TAG, e.toString());
            return false;
        }
    }

    private void loadMap(TiledMap map) {
        String sI = null;
        Blocked.clear();
        Event.clear();

        try{
            mapTiles = (TiledMapTileLayer)map.getLayers().get(0);
            mObjects = map.getLayers().get("Testing").getObjects();
        } catch (Exception e) {
            Gdx.app.log(TAG, e.toString());
        }


        Gdx.app.log(TAG, "Objects:"+mObjects.getCount());

        for(Iterator<MapObject> mObjs = mObjects.iterator(); mObjs.hasNext();){
        // I have set just about everything possible(I only have one object at the moment so mObj only gets set once.
            mObj = mObjs.next();
            Gdx.app.log(TAG, "Obj:"+mObj.getName());
            mObj.setColor(Color.GREEN);
            mObj.setOpacity(1f);
            mObj.setVisible(true);

//          try {
//              Method Test = getClass().getDeclaredMethod((String) mObj.getProperties().get("Func"));
//              Test.invoke(this);
//          } catch (Exception e) {
//              Gdx.app.log(TAG, e.toString());
//          }
        }

        Array<String> sTilesets = new Array<String>();
        TiledMapTile tile;

        try {
            for(Iterator<TiledMapTileSet> tilesets = map.getTileSets().iterator(); tilesets.hasNext();){
                    sI = tilesets.next().getName();
                    sTilesets.add(sI);
            }

            int tCount = sTilesets.size;
            for(int i = 0; i < tCount; i++){
                for(Iterator<TiledMapTile> tiles = map.getTileSets().getTileSet(sTilesets.get(i)).iterator(); tiles.hasNext();){
                tile = tiles.next();

                if(tile.getProperties().containsKey("blocked")){
                    //Gdx.app.log(TAG, "Tile:" + tile.getId() + " blocked!");
                }

                if(tile.getProperties().containsKey("name")){
                    //Gdx.app.log(TAG, "Name:" + tile.getProperties().get("name"));
                }

                boolean blocked = Boolean.parseBoolean(tile.getProperties().get("blocked", "false", String.class));
                boolean event = Boolean.parseBoolean(tile.getProperties().get("event", "false", String.class));

                Blocked.put(tile, blocked);
                Event.put(tile, event);
            }
        }
            Gdx.app.log(TAG, "Map Loaded!");
        } catch (Exception e) {
            Gdx.app.log(TAG, "Error:" + e.toString());
        }
    }

    public TiledMap getMap(){
        return gamemap;
    }
}

【问题讨论】:

    标签: java android libgdx collision-detection


    【解决方案1】:

    我最近在 GameDev 上 answered a similar question,被同样的问题困扰了一段时间。彻底的谷歌搜索最终让我找到了这个主题的a tutorial。我的意思是彻底。它似乎是整个互联网上唯一解决这个问题的方法。很奇怪。

    无论如何。我给出的答案和它基于的教程都使用 Box2d 来处理碰撞检测。我会全心全意地 建议您在制作游戏方面走这条路:如果您使用 Box2d,它会为您处理很多事情,但这确实意味着重新考虑您现有的很多代码.基本上,一切都与运动有关。如果您选择这样做,那么好旧的LibGDX wiki 可以帮助您入门(这是相关文章的直接链接)。

    如果您不想进入那个兔子洞,那么上面的链接仍然可以提供解决方案。我认为你出错的地方是试图直接绘制MapObjects。试试这个:

    MapObjects objects = map.getLayers().get("Obstacles").getObjects();
    
    for(MapObject object : objects) {
        if (object instanceof RectangleMapObject) {
            Rectangle rect = ((RectangleMapObject) object).getRectangle();
            // do something with rect...
        }
        else if (object instanceof PolygonMapObject) {
            Polygon polygon = ((PolygonMapObject) object).getPolygon();
            // do something with polygon...
        }
        else if (object instanceof PolylineMapObject) {
            Polyline chain = ((PolylineMapObject) object).getPolyline();
            // do something with chain...
        }
        else if (object instanceof CircleMapObject) {
            Circle circle = ((CircleMapObject) object).getCircle();
            // do something with circle...
        }
    }
    

    从那里你处理生成的形状(Rectangle 或你有什么)而不是MapObjects。他们有对碰撞检测有用的方法,比如overlaps()contains()等等。如果您只处理一种形状,那么在非 Box2d 游戏中它会让生活更轻松。例如,仅对 PolygonMapObject 使用 if 语句,并删除其他三个。

    【讨论】:

      【解决方案2】:



      我想你需要一种被阻塞的瓷砖的“映射”。所以你不能总是检查瓷砖是否被阻挡。这将需要很长时间才能获得瓷砖。
      这样做有不同的方法,但我使用了这个。
      我写了自己的“地图”。这个地图在我当前的 TiledMap 的维度上保存了一个数组。当我加载地图时,我确实在该 mapArray 中设置了一个值,所以我知道我是否可以在该 Tile 上移动。这看起来确实有点吓人,并且在更大的地图上需要一些时间,但它确实有效。

      private void setBlocked() {
          for (int i = 0; i < this.map.getLayers().getCount(); i++) {
              TiledMapTileLayer layer = (TiledMapTileLayer) this.map.getLayers()
                      .get(i);
              for (int y = 0; y < layer.getHeight(); y++) {
                  for (int x = 0; x < layer.getWidth(); x++) {
                      if (layer.getCell(x, y) != null
                              && layer.getCell(x, y).getTile().getProperties()
                                      .containsKey("blocked")) {
                          this.mapArray[x][y] = Config.CANTMOVEONPOSITION;
                      }
                  }
              }
          }
      }
      

      为了调试我渲染方块并用“mapState”的颜色填充它们,如下所示:

      if (this.map != null) {
                  for (int i = 0; i < this.map.width; i++) {
                      for (int j = 0; j < this.map.height; j++) {
                          switch (this.map.mapArray[i][j]) {
                          case Config.CHARSTATE:
                              // green
                              debugger.setColor(0, 1f, 0, Config.DEBUG_ALPHA);
                              break;
                          case Config.CANTMOVEONPOSITION:
                              // black
                              debugger.setColor(1f, 1f, 1f, Config.DEBUG_ALPHA + 0.1f);
                              break;
                          case Config.MONSTERSTATE:
                              // red
                              debugger.setColor(1f, 0, 0, Config.DEBUG_ALPHA);
                              break;
                          case Config.MOVETONEXTMAP:
                              // yellow
                              debugger.setColor(1f, 1f, 0, Config.DEBUG_ALPHA);
                              break;
                          default:
                              debugger.setColor(0, 0, 0, 0);
                              break;
                          }
                          debugger.rect(i * Config.TILE_SIZE, j * Config.TILE_SIZE,
                                  Config.TILE_SIZE, Config.TILE_SIZE);
                      }
                  }
                  debugger.end();
              }
      

      这不是优化的!因此,如果您有一张大地图并且只显示一个小框架,它仍然会绘制每个正方形。在这种情况下,height and width 是高度和宽度的 tilecount。
      我希望这确实回答了您的问题,或者您可以在帮助下找到自己的方式。
      问候

      【讨论】:

      • 恐怕您的回答与关于从对象层渲染地图对象的 q 无关。在瓦片级别上执行此操作假定瓦片层和那里的单元格导致在您的解决方案中导致有点可怕的完整地图瓦片解析和随后的重复数组。使用 q 中描述的地图对象和第一个答案是无限强大的,因为地图对象可以很容易地变形为 b2d 对象,并且不限于单个单元格大小。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      • 2012-11-29
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多