Java 使命令行驱动的基于转弯的rpg适应swing';s事件驱动范式

Java 使命令行驱动的基于转弯的rpg适应swing';s事件驱动范式,java,swing,user-interface,2d,Java,Swing,User Interface,2d,背景: 在过去的几个月里,我一直在利用空闲时间用Java开发一个基于回合的RPG。我只做了大约一年的编程,所以我的专业知识主要局限于命令行应用程序和面向对象编程原理,这些都是我在初级CS课程中学到的 开发一直进展顺利,直到我开始调整游戏,从从从命令行输入到使用我开始使用Swing构建的定制UI。这在很大程度上是因为基于命令行的输入允许我停止我正在做的一切,并等待来自扫描仪或类似的东西的输入,但从我在这里读到的线程(,)来看,Swing的事件驱动特性实际上不允许您在不中断EDT和冻结GUI的情况下

背景:

在过去的几个月里,我一直在利用空闲时间用Java开发一个基于回合的RPG。我只做了大约一年的编程,所以我的专业知识主要局限于命令行应用程序和面向对象编程原理,这些都是我在初级CS课程中学到的

开发一直进展顺利,直到我开始调整游戏,从从从命令行输入到使用我开始使用Swing构建的定制UI。这在很大程度上是因为基于命令行的输入允许我停止我正在做的一切,并等待来自扫描仪或类似的东西的输入,但从我在这里读到的线程(,)来看,Swing的事件驱动特性实际上不允许您在不中断EDT和冻结GUI的情况下等待任何东西,这对我来说是件坏事

问题:

虽然Swing对我来说很新奇,但我已经在主菜单上使用了它,并且看到了它如何能够很容易地应用到游戏中,在这些游戏中,数据相对集中在几个对象之间,这些对象利用用户的简单命令来移动或攻击,或者你拥有的东西。我的问题是,我的RPG在战斗场景中有2到16个活动角色,可以由用户控制,也可以由AI控制,可以使用任意数量的不同命令(包括16种不同的技能),玩家角色必须能够访问所有角色之间共有的资源库。可以说,我的游戏是由菜单驱动的。例如,我将发布一个从我在战斗中运行的循环中调用的方法:

//initializes a turn; written as a function to cut down on duplicate code
public battleData initializeTurn(battleData toInitialize){
    if(toInitialize.initializeSkill()) {
        if(toInitialize.initializeTarget(playerParty, playerMinions, 1) == 0)
            return initializeTurn(toInitialize); //recursive call if the user cancelled
    }                                            //the skill they selected.
    else {
        if(toInitialize.initializeTarget(enemyParty, enemyMinions, -1) == 0)
            return initializeTurn(toInitialize); //see above
    }
    return toInitialize;
}
此方法调用gameCharacter类中编写的两个函数initializeTarget和initializeSkill,从传递的两个目标数组中选择一个目标,并从角色的两个技能列表中选择一个技能。从gameCharacter类派生的是playerCharacter和Monster类,它们分别从用户输入和基本AI计算方法的返回值。因为我有很多关于技能和项目的数据存储在不同的类中,用户输入的行为不同,这取决于哪个角色获得输入,无论他们是选择目标还是当前选择的技能,以及他们在技能选择菜单范围内的位置,我发现很难制定一个算法,让我让整个事情都由事件驱动,因为事件可能意味着许多不同的事情,这取决于当前正在查看的菜单的哪一部分

解决方案:

我读过一些东西,比如swingworkers被用来处理后台任务,states被用来向不同的地方提供输入,Timer被用来定期更新图形组件,但我对Swing还不够熟悉,不知道现在最好的方法是什么。我更多的是寻找一个通用的算法来实现,而不是一个神奇的解决方案,它可以让我在不改变代码的情况下解决问题。到目前为止,我非常愿意对我所写的内容进行一些修改,所以不要害怕告诉我,如果你认为这会使程序变得更好,我将不得不重新进行一些修改


谢谢你对我的宽容;如果您需要更多的上下文,我很乐意解释或发布更多的代码。首先,我会发布更多内容,但我提到的大多数菜单都是1-200行,而且比实际复制更容易解释。

首先,您可以将GUI视为在更新屏幕时不做任何事情的东西,从而使问题变得稍微容易一些,与命令行相反,在等待输入时不执行任何操作。因为这是一个基于回合的游戏,所以必须对回合何时被认为准备好进行计算有要求。通常,当用户完成输入时会发生这种情况。在你的例子中,根据我收集的信息,输入基本上是不同游戏角色的顺序。因此,每次用户命令执行某项操作(单击游戏角色的命令按钮)时,都必须进行类似于
isReadyCompute()
的检查。当该方法返回true时,可以调用
computeTurn()
。下面是一些粗略的代码表示。您需要添加一些与游戏性相关的检查,但它应该给出从何处开始的想法

skillButton1.addActionListener(e -> {
    // change cursor to "select" type cursor
    skill1 = true;
});

public class Mouse implements MouseListener {
    public void mouseClicked(MouseEvent e) {
         // get mouse x y
         // find target game character at x y or if none then return
         // remember the character as target
         // of skill1 of selected character
         // and count this as order complete for selected character
         skill1 = false;
         // change cursor to normal

         if (isReadyToCompute()) computeTurn();
    }
}
总体思路是,您不需要循环,因为GUI已经有了自己的内部循环,并且它在EDT上运行。EDT捕获并分派由操作和鼠标侦听器处理的事件。当使用命令行时,您等待侦听输入事件的扫描器,类似地,在GUI中,您等待前面提到的侦听器,这些侦听器依次侦听按钮按下或鼠标事件。有关如何编写侦听器的详细信息,请参阅Oracle官方教程:


如果你觉得一切都一样,我建议你改用JavaFX,它是一个更丰富的图形框架,是游戏的更好选择,是Swing的继承者

可能。总而言之,您选择角色,然后选择技能/顺序,然后选择目标,然后选择2-16个角色。最后战斗画面(单回合)通过,然后你准备好下一回合了吗?如果我误解了,请纠正我something@AlmasB这就是游戏目前的工作方式,但我不确定如何在事件驱动的环境中实现该算法,或者通常如何让它与Swing一起工作,因为角色、技能和目标的选择取决于等待用户输入,但是如果不中断EDT并冻结GUI,就无法真正做到这一点。至少据我所知,但这就是我问的真正原因。我在早些时候实现主菜单时曾与action listeners打过交道,但只是检查输入的当前状态似乎是一个有效的解决方案。我会的