Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functionality for generated maps #139

Closed
TheRamenChef opened this issue Jun 19, 2018 · 9 comments
Closed

Add functionality for generated maps #139

TheRamenChef opened this issue Jun 19, 2018 · 9 comments
Assignees
Labels
Milestone

Comments

@TheRamenChef
Copy link
Collaborator

LITIEngine currently has very little support for maps generated at runtime. I would like to have this functionality for the game I’m working on.

@steffen-wilke
Copy link
Contributor

In general, I think this is a good idea. @TheRamenChef could you describe your requirements in more detail? What are the required engine extensions in you eyes?

@TheRamenChef
Copy link
Collaborator Author

Basically, I want to be able to make procedurally-generated levels for better replay value.

@TheRamenChef
Copy link
Collaborator Author

Any updates on this feature?

@steffen-wilke
Copy link
Contributor

In general, I think most of the API in the de.gurkenlabs.litiengine.tilemap and de.gurkenlabs.litiengine.tilemap.xml namespaces should already allow for generating maps from code. We've done this in a few games we made in the past.

However, I still think there might be some missing or non-public APIs that we didn't come across yet. I'll investigate this and check for any missing pieces.

@steffen-wilke
Copy link
Contributor

I just wrote a quick test that checks for the available methods of the XML implementation compared to what is available on the interfaces (public API).

de.gurkenlabs.litiengine.environment.tilemap.xml.CustomProperty ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.CustomPropertyProvider ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.Frame ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.package-info ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.PolyShape ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.Terrain ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.TileAnimation ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.TileOffset ✔
de.gurkenlabs.litiengine.environment.tilemap.xml.TilesetEntry ✔

de.gurkenlabs.litiengine.environment.tilemap.xml.Blueprint

  • build missing
  • keepIds missing
  • getItems missing
  • getBounds missing
  • setPolyline missing

de.gurkenlabs.litiengine.environment.tilemap.xml.GroupLayer

  • setRenderType missing
  • setOpacity missing

de.gurkenlabs.litiengine.environment.tilemap.xml.ImageLayer

  • setRenderType missing
  • setOpacity missing

de.gurkenlabs.litiengine.environment.tilemap.xml.Layer

  • setRenderType missing
  • setOpacity missing

de.gurkenlabs.litiengine.environment.tilemap.xml.MPublic APImage

  • getHeight missing
  • getWidth missing

de.gurkenlabs.litiengine.environment.tilemap.xml.MapObject

  • getBounds missing
  • setPolyline missing

de.gurkenlabs.litiengine.environment.tilemap.xml.MapObjectLayer

  • setRenderType missing
  • setOpacity missing

de.gurkenlabs.litiengine.environment.tilemap.xml.Text

  • getFontName missing
  • getPixelSize missing
  • isBold missing
  • useKerning missing
  • isItalic missing
  • isStrikeout missing
  • isUnderlined missing

de.gurkenlabs.litiengine.environment.tilemap.xml.Tile

  • setTileCoordinate missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TileChunk

  • getValue missing
  • getHeight missing
  • getX missing
  • getWidth missing
  • getY missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TileData$Compression

  • isValid missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TileData$Encoding

  • isValid missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TileData

  • encode missing
  • getValue missing
  • setValue missing
  • getEncoding missing
  • setEncoding missing
  • setCompression missing
  • getCompression missing
  • getTiles missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TileLayer

  • setRenderType missing
  • setOpacity missing

de.gurkenlabs.litiengine.environment.tilemap.xml.Tileset

  • load missing
  • finish missing
  • saveSource missing
  • isExternal missing
  • updateTileTerrain missing

de.gurkenlabs.litiengine.environment.tilemap.xml.TmxMap

  • setHeight missing
  • setWidth missing
  • finish missing
  • setPath missing
  • setVersion missing
  • setTileWidth missing
  • setStaggerIndex missing
  • setOrientation missing
  • setStaggerAxis missing
  • setHexSideLength missing
  • setTiledVersion missing
  • setTileHeight missing
  • setRenderOrder missing
  • getExternalTilesets missing

As a first step, we should iterate over these missing methods and check which ones should be included in the public interface. Then we can define further API that simplifies map generation, e.g. a helper class that simplifies the generation (also see #329 and This forum post)

@steffen-wilke steffen-wilke self-assigned this Apr 4, 2020
@ghost
Copy link

ghost commented Apr 4, 2020

Not to be greedy, but can you point a link to these past games?
Litiengine doesn't seem to be automagically reading & using collision boxes from tmx files.
It would be helpful to see how you get that to work

@steffen-wilke
Copy link
Contributor

steffen-wilke commented Apr 4, 2020

Not to be greedy, but can you point a link to these past games?

Sorry, these were internal projects. But I'm currently working on extending Gurk Nukem with a mechanism to generate maps at runtime as an example project.

In general: collision boxes are just MapObjects with the type MapObjectType.COLLISIONBOX.
Our utiliti editor is basically the best publically available example for adding map objects to a map.
Basically, what you need is a IMapObjectLayer and then you can add as many objects of different types as you desire:

Adding a mapobject to a layer

public void add(IMapObject mapObject, IMapObjectLayer layer) {
if (layer == null || mapObject == null) {
return;
}
layer.addMapObject(mapObject);
Game.world().environment().loadFromMap(mapObject.getId());
Game.window().getRenderComponent().requestFocus();
this.setFocus(mapObject, false);
this.setEditMode(EDITMODE_EDIT);
}

Creating a new MapObjectLayer

if (map.getMapObjectLayers().isEmpty()) {
// make sure there's a map object layer on the map because we need one
// to add any kind of entities
MapObjectLayer layer = new MapObjectLayer();
layer.setName(DEFAULT_MAPOBJECTLAYER_NAME);
map.addLayer(layer);
}

Creating a new MapObject

private IMapObject createNewMapObject(MapObjectType type) {
final Rectangle2D newObjectArea = this.getMouseSelectArea(true);
IMapObject mo = new MapObject();
mo.setType(type.toString());
mo.setX((float) newObjectArea.getX());
mo.setY((float) newObjectArea.getY());
// ensure a minimum size for the new object
float width = (float) newObjectArea.getWidth();
float height = (float) newObjectArea.getHeight();
mo.setWidth(width == 0 ? 16 : width);
mo.setHeight(height == 0 ? 16 : height);
mo.setId(Game.world().environment().getNextMapId());
mo.setName("");
switch (type) {
case PROP:
mo.setValue(MapObjectProperty.COLLISIONBOX_WIDTH, (newObjectArea.getWidth() * 0.4));
mo.setValue(MapObjectProperty.COLLISIONBOX_HEIGHT, (newObjectArea.getHeight() * 0.4));
mo.setValue(MapObjectProperty.COLLISION, true);
mo.setValue(MapObjectProperty.COMBAT_INDESTRUCTIBLE, false);
mo.setValue(MapObjectProperty.PROP_ADDSHADOW, true);
break;
case LIGHTSOURCE:
mo.setValue(MapObjectProperty.LIGHT_COLOR, Color.WHITE);
mo.setValue(MapObjectProperty.LIGHT_SHAPE, "ellipse");
mo.setValue(MapObjectProperty.LIGHT_ACTIVE, true);
break;
case COLLISIONBOX:
mo.setValue(MapObjectProperty.COLLISION_TYPE, Collision.STATIC);
break;
case SPAWNPOINT:
default:
break;
}
this.add(mo);
return mo;
}

If you'd rather use the engines Entity implementation to create your MapObject you could have a look at the MapObjectSerializer.

@ghost
Copy link

ghost commented Apr 4, 2020

Genius, that will work in theory. I'll check it out

steffen-wilke added a commit that referenced this issue Apr 4, 2020
Previously, it was necessary to provide static TileData that was not considered to be changed afterwards. With this change, it's possible to change tiles on a map at runtime.
The main API for this is ITileLayer.setTile.

Don't throw InvalidTileLayerException, try to avoid crashing a game over all other code-design.

Issue #139
steffen-wilke added a commit that referenced this issue Apr 4, 2020
@steffen-wilke
Copy link
Contributor

steffen-wilke commented Apr 4, 2020

96be92d introduces a new API to support generating maps: Resources.maps().generate(...)

Usage

IMap generatedMap;
try (MapGenerator generator = Resources.maps().generate(MapOrientations.ORTHOGONAL, "mymap", 100, 100, 16, 16, Resources.tilesets().get("tileset.tsx"))) {
  tileLayer = generator.addTileLayer(RenderType.GROUND, (x, y) -> {
    if (x == y) {
      // draw a diagonal in another tile color
      return 2;
    }

    // fill the entire map with this tile
    return 1;
  });

  // set an explicit tile at a location
  tileLayer.setTile(10, 10, 3);

  // add a collision box to the map
  generator.add(new CollisionBox(0, 50, 100, 10));

  generatedMap = generator.getMap();
}

@steffen-wilke steffen-wilke added this to the v0.4.21-alpha milestone Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants