我一直在使用artemis-odb和libGDX制作基于回合制的基于平铺地图的游戏。
我想要地图的不同地形类型,如草地,沙地,水面,山脉等等,这些不同的地形类型中的每一种都有不同的运动成本,以及与游戏相关的各种附加属性。
我现在正在考虑几种不同的方法:
我可以将地图设为系统GameMapSystem
,并让每种类型的地形由一个实体代表,其中包含每种地形类型的相关组件(TerrainStats
,偶尔会有拼写效果组件{例如{1}}。我主要关心的是如何管理切片到地形类型实体的映射。从概念上讲,应该像使用与地形实体的id相对应的值维护Exploding
一样简单,但是在这种情况下,临时标记组件(int[][]
)将附加到所有给定地形一次打字。这似乎不太理想。那么那么我需要为每个瓷砖设一个单独的实体吗?如果我这样做,我不是为实体框架创造额外的开销吗?
我还考虑制作游戏地图和地形类型POJOS,然后只使用特殊效果的标记组件创建标记实体。然而,这样做,看起来我会在willy-nilly周围传递Exploding
对象,以便各种系统能够对其进行处理(用于渲染,碰撞,路径等)。另外,我的游戏地图是否还需要在任何给定时间跟踪地图上的实体与他们的位置以便进行我的路径逻辑?如果可能的话,我更愿意将实体的管理完全保留在实体框架的范围内,因为这意味着更容易维护。
我很好奇是否有任何方法我还没有检查过。否则我会倾向于方法#2,除非有一些方法来修复我忽略的方法#1。
答案 0 :(得分:1)
我最终使用了两种方法中的东西。以下代码片段应该有助于说明我采用的方法:
class TerrainType {
public String displayName;
public String regionName;
public int movementCost;
/* additional properties omitted */
/* constructors omitted */
}
此结构包含有关地形类型的相关信息,包括移动成本和其他与游戏相关的统计数据(为简单起见,我省略了其余部分),要检查的地形类型的显示名称,以及TextureRegion
从我的渲染器对我抱着的TextureAtlas
中拉出来。{/ p>
class GameMapSystem extends EntityProcessingSystem {
@Mapper private ComponentMapper<MapPosition> pm;
@Mapper private ComponentMapper<SolidObject> som;
private ListMultimap<MapPosition, Entity> entityByLocation;
private int[][] map;
private int width, height;
private Array<TerrainType> terrainTypes;
/**
* Accepts an Array of TerrainType objects and an 2d integer array with
* values corresponding to indices into the array for the correct type.
*
* In my case, these values are gleaned by reading a level description
* file, but any source should be fine.
*/
public GameMapSystem(Array<TerrainType> terrainTypes, int[][] map) {
super(Aspect.getForAll(MapPosition.class));
this.terrainTypes = terrainTypes;
this.map = map;
this.width = map.length;
this.height = map[0].length;
this.entityByLocation = ArrayListMultimap.create();
}
public boolean isOccupied(int x, int y) {
List<Entity> entities = entityByLocation(new MapPosition(x, y));
for(Entity e : entities) {
if(som.has(e)) {
return true;
}
}
return false;
}
@Override
protected void inserted(Entity e) {
this.entityByLocation.put(pm.get(e), e);
}
@Override
protected void removed(Entity e) {
this.entityByLocation.remove(pm.get(e), e);
}
/* additional EntityProcessingSystem overrides omitted */
}
这个EntityProcessingSystem
然后以被动模式附加到我的世界。在这个系统中,实际上不应该为我的世界做任何处理,我真正想要的是能够收听inserted
和removed
事件以将实体放入地图。一个经理在这种情况下会过度杀戮,因为它会告诉我每个实体被插入或移除,我只关心地图相关的(或者更具体地说是地图相关的位置)。然后我有一些单独的路径查找逻辑,只需从世界对象请求这个被动系统,就会消耗额外的(这里没有看到)方法来引导AI。
为了完整性,MapPosition
类也如下所示。重要的是包含equals()
和hashcode()
以帮助将MapPosition
用作集合中的关键字。
public class MapPosition extends Component
{
public int x, y;
public MapPosition(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object other) {
if(!(other instanceof MapPosition)) {
return false;
}
MapPosition pos = (MapPosition)other;
return (pos.x == this.x && pos.y == this.y);
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + this.x;
hash = 59 * hash + this.y;
return hash;
}
}
我可能会尝试找到一个比最终使用番石榴Multimap
更方便的数据结构,但它现在可以正常工作,我觉得很容易为这些类充实其余的公共API 。如果这个答案对其他人有帮助,请记住,ArrayListMultimap
对此实现的性能未经过严格测试!
答案 1 :(得分:0)
我正在弄清楚同样的事情。只想分享Artemis开发人员关于这个案例的一些答案,这些答案实际上没有回答,但值得一提:
http://slick.ninjacave.com/forum/viewtopic.php?p=20125#p20125 http://slick.ninjacave.com/forum/viewtopic.php?p=20136#p20136
老实说,Artemis仍然被认为是实验性的#34;。这是一个我想要看的新模式,很有前景,但仍然存在那些我没有真正找到答案的问题,系统扮演的角色有多大,你没有把它放到实体中/组件等在我脑子里发生了一些关于实体/组件在看起来像是非实体事物(如地形,背景音乐等)时扮演的角色有多大的争论。 p>
他给出的另一个暗示是区分:
所以看起来我们需要探索实际的解决方案,因为范式不够成熟,无法拥有正确的解决方案。答案