Java控制台游戏开发 | 方法

3
好的,让我详细说明我的困境。
我正在使用Java制作控制台游戏。它不会很简单,但我也不希望它变得非常高级。我只是想使用我学到的基础知识来测试自己的技能。我已经尝试了几次,但总是遇到同样的“问题”。
虽然这不是一个实际的问题,但我可以做得更好。最好的解释方法就是展示一些示例代码。
这是我的主类。我们将其称为“Main.java”。
package com.mattkx4.cgamedev.main;

public class Main {
    public static void main(String[] args) {

    }
}

好的,现在让我们在Main.java中创建一个新方法。我们将这个方法称为“Start”。我们的Main类现在如下所示:

package com.mattkx4.cgamedev.main;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

    }

    public static void start() {
        System.out.println("This is the start.");
        Scanner s = new Scanner(System.in);
        System.out.println("Enter \"NEXT\" to continue.");
        String in = s.nextLine();

        if(in.equalsIgnoreCase("NEXT")) {
        }else{
            System.out.println("Please input \"NEXT\".");
            start();
        }
    }
}

现在我们将添加两个新方法。我们将它们命名为 "middle" 和 "end"。我们的最终类现在如下所示:
package com.mattkx4.cgamedev.main;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        start();
    }

    public static void start() {
        System.out.println("This is the start.");
        Scanner s = new Scanner(System.in);
        System.out.println("Enter \"NEXT\" to continue.");
        String in = s.nextLine();

        if(in.equalsIgnoreCase("NEXT")) {
            middle();
            s.close();
            System.exit(0);
        }else{
            System.out.println("Please input \"NEXT\".");
            start();
        }
    }

    public static void middle() {
        System.out.println("This is the middle.");
        System.out.println("Let's move on to the end.");
        end();
    }

    public static void end() {
        System.out.println("This is the end.\nFinishing up, and heading back to the start() method to close program.");
    }
}

我认为这是一个非常低效的程序,特别是在编程方面。除了在方法内调用其他方法推进程序之外,还有其他方法来完成这个程序。
我的问题总结如下:上述代码是否是编写控制台游戏的最有效方式?
提前感谢您的帮助!如果您有任何问题,我很乐意回答。 -马修
5个回答

5

有很多种回答你的问题。我只列举一些基本的事情。

  1. Your design is linear and completely rigid. Unflexible. Most applications like this, rather than chaining any methods or the like, store a state somehow. This is often achieved with an enum. It's important to understand how state-based programming works. So you might have something like:

    public enum GameState {
        LOAD, START, STOP, BEGIN, MIDDLE, END, GAME_OVER // ... and so on
    }
    
  2. You're using a bunch of static methods. This is certainly not what you want to do. It completely abandons any object-orientation. If you're making a game world, you will, ideally, have a class for every distinct object in your world, and they will be arranged in a logical hierarchy, by extends-ing each other or implements-ing different interfaces.

  3. You will need to learn concurrency. Your user input will almost necessarily come asynchronously to the rendering of your game, if it has any sophistication at all. At the very, very least, you'll probably at least need Swing to create a GUI.

所以,仅凭这三个非常基本的注释,您需要学习面向对象编程, 多态性并发编程,以及所有可用于您的各种数据结构。坦白地说,您的示例项目只有Java 101项目的复杂度。(我并不是要说您不好。)如果您计划制作真正的游戏,在您能够取得实质性进展之前,您需要更多的基础知识。

您能想到更大的目标并且对编程有野心是很好的。但是将这个宏大的梦想拆分成可管理的块会让你更快更顺利地达成目标,并防止你失去信心。

祝你好运!


作为一个旁注,如果您开始编写一些简单的游戏(甚至像基于控制台的Hangman或Tic-Tac-Toe这样简单的东西),请访问Code Review Beta。我们将非常乐意为您的代码进行详细的审核,并帮助您成为一名资深的程序员!这是一个良好的社区,有很多非常建设性的批评。我在那里帮助过人们(使用Java)并在学习Python时得到了很多帮助。

1
非常感谢您提供如此详细的答案!我会努力学习这三个主题,直到我对它们感到舒适为止!这个问题是为了寻找制作游戏的更好方式而提出的。而不是我一直在做的“线性”和“不灵活”的编程。谢谢! - Mattkx4
1
@Mattkx4 我期待有一天在Steam上购买你的独立游戏! :) - asteri
Jeff的回答很好。对于OP,Victor的回答描述了一种相当可靠的技术(使用主游戏循环)来实现Jeff所描述的内容。此外,第2项中描述的概念是多态性;多态性是任何编程语言中为将来留下代码扩展空间的绝佳方式。最后,DesignsbyZephyr有一个不完整但非常信息丰富的Java游戏引擎教程,你可能想要研究一下。 - user3507600
@user3507600 感谢您指出游戏循环答案。这是另一种在开始阶段掌握的好技巧。 - asteri
@JeffGohlke 我仔细研究了面向对象编程的文档,学到了很多!以前我在Java中编程时,所有东西都在类声明后面的大括号中!现在我知道不是所有东西都是一个类!现在我知道了接口、对象、类等等!谢谢你给我更进一步的推动 :) - Mattkx4
显示剩余4条评论

3

嗯,我不太明白这与性能或优化有什么关系。但通常你使用类和方法来组织你的程序。

话虽如此,在你的start方法中有一个巨大的错误。你应该避免不必要的递归,改用循环,并删除exit调用:

public static void start() {
    System.out.println("This is the start.");
    Scanner s = new Scanner(System.in);
    System.out.println("Enter \"NEXT\" to continue.");
    String in = s.nextLine();

    if(in.equalsIgnoreCase("NEXT")) {
        middle();
        s.close();
        System.exit(0);
    }else{
        System.out.println("Please input \"NEXT\".");
        start();  // <-- recursion!
    }
}

最好像这样做:
public static void start() {
    System.out.println("This is the start.");
    Scanner s = new Scanner(System.in);

    System.out.println("Enter \"NEXT\" to continue.");

    while ( !s.nextLine().equals("NEXT")) {
        System.out.println("Please input \"NEXT\".");
    }

    middle();

    // you probably also want to put "end();" here - it is not called in the original code
    s.close();
}

谢谢你的回答!我现在可以看到有很多不同的设计这种类型游戏的方法了!我也会记住你使用 while 循环和扫描器检查 :) 那可能非常有用。 - Mattkx4

3

我猜你想要建立的是应用程序的主体框架。我建议搜索“游戏循环”。下面有许多关于此方面的好文章。

对于一般解决方案,算法在大规模上大致如下:

while (notExit()) {
   event = getNextEvent(); // this can be the user keyboard input or mouse
   renderGame(); // display the graphics on the screen
   doGameLogic(event); // do the game logic according to the events occurred
}

稍后,您必须考虑屏幕每秒绘制的次数(FPS)和计算更改的次数(物理帧每秒)。与GUI编程的任何类比都只是纯属巧合。开个玩笑,不是巧合,事实上GUI和游戏编程共享一个线程,起到事件分发线程的作用。如需更多信息,建议阅读此教程:http://sol.gfxile.net/gp/index.html。希望对您有所帮助!

非常感谢您提供的想法!我很感激您的考虑! - Mattkx4
祝你好運,伙計! - Victor

2

对于应用程序/游戏,如何组织结构真的取决于它的类型。

在这种情况下,您可能会发现有一种控制方法很有用,它可以按正确的顺序运行函数并具有您的“流程”逻辑。

在更复杂的游戏中,此方法将处理用户输入,指导他们进入不同的房间/级别/等级。您甚至可以有处理子部分的较小控制方法。

例如,您可以编写一个playGame方法,该方法调用registerPlayer(),以便处理获取玩家的姓名和其他信息。当该方法返回时,playGame将调用levelOne()方法,以此类推。

只需要将其拆分为逻辑单元即可!


我理解了你回答的第二部分,包括其中的子部分等等。例如,如果你有一个getUserInfo()方法,你会在该方法内运行getName()、getAge()和getGender()(当然是理论上的方法),但你在第二段中提到了一个控制方法。你能否详细解释一下你的意思?- Matthew - Mattkx4
我想最好的解释方式是,假设你有一个基本的文本游戏,可以输入北、南、东或西。你的“控制方法”将是我所说的playGame,并且将处理获取用户输入、验证它,然后根据用户输入将程序流程引导到适当的方法。 - Ford Filer
好的,感谢澄清!我现在接受你的答案,因为它确实回答了我的问题!编辑:实际上,我太菜了,无法回答你的问题,所以等我变得更厉害了再回答吧 :) - Mattkx4
2
我知道这比较高级,但大多数游戏将其处理为有限状态机。 - spudone

2

我的头脑中的解决方案:

创建类

class Location{
public Location( String locationId, String desctiption, List<String> exit){
//populate fields
}

private final String locationId;
private final String desctiption;
private final List<String> exits;
//getters ommited
}

那么你可以有3个位置;

start = new Location("START","This is the start.",Arrays.asList("middle"));
middle= new Location("middle","This is the middle.\nLet's move on to the end.",Arrays.asList("end"));
end= new Location("end","This is the end.",null);

现在是你的启动类

公共类游戏{ 地点 = 新哈希表();

public Game() {
    locations.put("START", new Location("START", "This is the start.",
            Arrays.asList("middle")));
    locations.put("middle",
            new Location("middle",
                    "This is the middle.\nLet's move on to the end.",
                    Arrays.asList("end")));
    locations.put("end", new Location("end", "This is the end.", null));
}

public static void main(String[] args) {
    Game game = new Game();
    game.start();

}

private void start() {
    visitLocation(locations.get("START"));

}

public void visitLocation(Location location) {
    System.out.println(location.getDescription());

    if (location.getExits().isEmpty()) {
        return;
    }

    Scanner s = new Scanner(System.in);
    String in = "";
    do {
        System.out.println("Choose exit from location : ");
        for (String exit : location.getExits())
            System.out.print(exit + " ");
        in = s.nextLine();
    } while (!location.getExits().contains(in));
    s.close();

    visitLocation(locations.get(in));
}

}

这还不是最好的,但我认为它会给你一些想法。


肯定得到了一些想法!非常感谢! - Mattkx4
@Mattkx4 这个基本概念是创建您的位置/状态对象以及它们之间的转换,然后根据输入改变状态。 - user902383
是的,这就是我从这段代码中得到的!我一定会使用它! - Mattkx4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接