我想为我的城市建筑游戏创建一个保存游戏系统,该系统不需要玩家输入城市名称。允许无限保存游戏也很重要,因此我不能仅使用保存插槽来解决问题。在一点帮助下,我设计了一个系统,该系统允许玩家选择输入名称,如果他们没有输入,游戏将根据现有的保存名称确定默认名称。

首先,我只是在数所有现有的世界,然后将该数字添加到"world"中以获得名称。但是,我担心一个极端的情况,例如有人将创造5个世界,然后删除"world4",然后游戏会再次建议名称"world5",如果玩家不注意,他们的保存将被覆盖。

当用户选择开始一个新游戏时,将出现一个由正确的字符串填充的TextField,该字符串为"world",后跟下一个未使用的数字。

String startName = this.getFirstUnusuedWorldName(this.getNumWorlds());
this.worldNameField = new TextField(startName, this.skin);


这是getNumWorlds()方法:

private int getNumWorlds() {
    FileHandle[] files = Gdx.files.local("worlds/").list();
    int numDirectories = 0;
    for (FileHandle handle : files) {
        if (handle.isDirectory()) {
            numDirectories++;
        }
    }
    return numDirectories;
}


这是getFirstUnusuedWorldName方法:

private String getFirstUnusuedWorldName(int numWorlds) {
    FileHandle[] files = Gdx.files.local("worlds/").list();
    if (files.length == 0) {
        return "world1";
    }

    ArrayList<String> possibleNames = new ArrayList<String>();
    for (int i = 1; i <= numWorlds + 1; i++) { //world names start with 1, need to search 1 past length
        possibleNames.add("world" + String.valueOf(i));
    }
    for (String possibleName : possibleNames) {
        boolean containsName = false;
        for (FileHandle file : files) {
            if (file.name().equals(possibleName)) {
                containsName = true;
            }
        }
        if (!containsName) {
            return possibleName;
        }
    }

    return "world1";
}


我希望有更好的方法来做到这一点。

#1 楼

您设法做正确的事,但是您做的方式有点...我们该怎么说...?扭曲吗?向后?非最佳选择!

您的方法:


获取目录中所有文件的列表
遍历一个范围并将可能的名称添加到列表中
浏览可能的名称并检查其是否与现有文件匹配

我对此的评论:


使用正确的数据结构将极大地帮助您这里。将现有文件名添加到Set<String>将使查找时间为\ $ O(1)\ $。
完全没有必要将名称添加到列表中,因为之后您可以直接遍历该列表。
通过特定范围也是不必要的。从1开始循环,直到找到一个空闲点才停止。
这也将使不需要特殊情况的files.length == 0

我们可以得到以下结果:

private String getFirstUnusuedWorldName() {
    FileHandle[] files = Gdx.files.local("worlds/").list();
    Set<String> fileNames = new HashSet<String>();
    for (FileHandle handle : files) {
        fileNames.add(handle.getName());
    }

    for (int i = 1; ; i++) {
        String name = "world" + i;
        if (!fileNames.contains(name)) {
            return name;
        }
    }
}


请注意,for -loop中没有停止条件(您迟早不需要一个,将有一个空白点)。

还要注意,您不再需要int numWorlds参数。

#2 楼

借助播放器@Quill进行编辑。

假设播放器不在乎分配给文件的名称,那么浏览文件树并为可能的用户交互设置异常似乎是很多工作。 >
您似乎正在搜索要添加到基本世界名称的唯一字符串。一个容易以时间戳记的形式获得,例如基于基本世界名称,年,月,时,分和秒的world20150709132530。很抱歉,由于我不熟悉该语言,所以无法提供代码示例,但这应该可以在参考文档中轻松获得。移至其他时区,夏季时间或时钟重新同步。在所有情况下,如果用户在新时间范围内保存与前一个时间范围相同的“第二秒”,则会出现问题。使用UTC可以消除前两个错误,但是如果用户查看当前不在UTC时区的国家/地区的文件名,则会给用户增加一层困惑。

评论


\ $ \ begingroup \ $
该名称用于填充播放器可见的TextField,所以在我看来,最好不要使用奇数。有趣的方法!
\ $ \ endgroup \ $
–巴佐拉
2015年7月9日在15:14

\ $ \ begingroup \ $
world-2015-Jul-09-T13:25:30更好吗?使用例如字符串文件名= new SimpleDateFormat(“'world'-yyyy-MMM-dd-'T'HH:mm:ss”)。format(new Date());
\ $ \ endgroup \ $
– pbeentje
15年7月10日在8:04



\ $ \ begingroup \ $
@pbeentje我认为世界上没有一个允许在文件名中使用的OS。
\ $ \ endgroup \ $
–西蒙·福斯伯格
15年7月13日在16:45

\ $ \ begingroup \ $
@SimonAndréForsberg遵循“单一Unix规范”文件名规则的任何操作系统都允许使用除NUL和正斜杠之外的任何字符。其中包括OS X和Linux,分别是iOS和Android的基础。请参阅开放组基本规范。
\ $ \ endgroup \ $
–杰瓦
2015年9月2日15:03