就像我在标题中说的那样,我在RPG中有一个循环,我正在制作高中。这是主要的循环,它按照时间顺序设置您的一天来执行单个序列。我的问题是我怎么能这样做,以便检查boolean
"击败"或boolean
"丢失" (指游戏的状态)在循环中的每个方法之后都被跳转到了真,但仍然将这些方法保持在一个循环中。嵌套在if循环中的if语句是唯一的方法吗?
while (!g.getBeat() || g.getLost())
{
g.wakeUp();
g.goToSchool();
g.beforeLunch();
g.lunchActivity();
g.afterLunch();
g.afterSchool();
g.home();
g.sleep();
}
答案 0 :(得分:3)
你必须手动完成。为了帮助您编写少量代码,请创建一个检查两种条件的方法:
private boolean stopTheLoop() {
return g.getBeat() || g.getLost();
}
现在,在每个方法之后使用检查将循环转换为无限:
while (true) {
g.wakeUp();
if (stopTheLoop()) break;
g.goToSchool();
if (stopTheLoop()) break;
g.beforeLunch();
if (stopTheLoop()) break;
...
}
答案 1 :(得分:3)
您可以通过引入状态来使用switch语句:
int state = 0;
while (!g.getBeat() || g.getLost())
{
switch (state) {
case 0:
g.wakeUp();
break;
case 1:
g.goToSchool();
break;
case 2:
g.beforeLunch();
break;
case 3:
g.lunchActivity();
break;
case 4:
g.afterLunch();
break;
case 5:
g.afterSchool();
break;
case 6:
g.home();
break;
case 7:
g.sleep();
break;
default:
// some error handling, depending on your logic,
// or perhaps state = -1 to restart
}
state++;
}
答案 2 :(得分:3)
没有任何“内置”方法可以做到这一点,但通过一些编码,一切皆有可能。
首先,无论你如何处理这个问题,我都会将结束条件包装到一个方法中,只是为了让事情变得更方便:
public class Game {
// method, members, etc...
public boolean isOver() {
return !getBeat() || getLost();
}
}
现在,首先想到的选择是手动执行此操作:
while (!g.isOver()) {
g.wakeUp();
if (g.isOver()) {
break;
}
g.goToSchool();
if (g.isOver()) {
break;
}
// etc...
}
但这涉及很多代码,并不太优雅。
或许更多的OO方法是在处理程序类中扭曲每个这样的调用:
public abstract GameStageHandler (Game g) {
protected Game g;
public GameStageHandler (Game g) {
this.g = g;
}
/**
* Play a stage in the game
* @return Whether the game should go on or not after this stage
*/
public boolean play() {
performStage();
return !g.isOver();
}
public abstract void performStage();
}
并在游戏的每个阶段实施它。例如。对于wakeUp()
阶段你有:
public abstract WakeUpHandler (Game g) {
public WakeUpHandler (Game g) {
super(g);
}
@Override
public void performStage() {
g.wakeUp();
}
}
然后,在main方法中,你可以有一个这样的处理程序数组,并迭代它们:
List<GameStageHandler> handlers = ...;
while (!g.isOver()) {
for (GameStageHandler handler : handlers) {
if (!g.play()) {
break;
}
}
}
答案 3 :(得分:2)
这可能超出了您的作业范围,因为您注意到该课程尚未覆盖Runnable
。然而,这是一个有趣的问题,挑战在于提出一种简洁而优雅的方式来表示它,同时避免尽可能多的重复。这是一个使用Java 8和函数式编程技术的解决方案。
第一个见解是看每个游戏动作或步骤可以表示为lambda表达式或方法引用。我假设您有一个Game
课程。每个这样的步骤都将Game
实例作为参数(或接收者),因此可以键入&#34;消费者&#34; Game
个实例。因此,我们可以将它们放入数据结构中:
List<Consumer<Game>> actions = Arrays.asList(
Game::wakeUp,
Game::goToSchool,
Game::beforeLunch,
Game::lunchActivity,
Game::afterLunch,
Game::afterSchool,
Game::home,
Game::sleep);
现在我们将它们放在数据结构中,我们可以遍历它们:
for (Consumer<Game> action : actions) {
action.accept(game);
}
当然,我们想在每次动作后检查游戏是否结束。假设您在isOver
类上有一个检查正确终止条件的方法Game
。然后你可以这样做:
for (Consumer<Game> a : actions) {
a.accept(game);
if (game.isOver()) {
break;
}
}
这只会持续一天的比赛。大概你想要无限期地运行游戏,直到达到终止状态。为此你需要一个外部循环,并且终止检查必须突破外部循环:
outer:
while (true) {
for (Consumer<Game> a : actions) {
a.accept(game);
if (game.isOver()) {
break outer;
}
}
}
这本身就足够了:你有一个游戏动作列表,以及一个无限期运行的循环,检查每个动作后的终止条件。
但等等,还有更多!这里仍有相当数量的样板,可以使用Java 8的一些流功能来消除。考虑使用noneMatch
方法可以针对谓词测试流的每个元素。当其中一个谓词返回true时,此方法终止。
由于每个动作都有类型Consumer<Game>
,我们需要一个小帮助函数将每个动作转换为谓词:
static Predicate<Consumer<Game>> stepAndCheck(Game game) {
return c -> { c.accept(game); return game.isOver(); };
}
现在我们可以按如下方式运行一天中的所有操作:
actions.stream().noneMatch(stepAndCheck(game))
要无限期地运行游戏,我们只需将其包装在while循环中。由于noneMatch
返回true
,如果它说没有任何谓词匹配,我们将其设为循环条件并将循环体留空:
while (actions.stream().noneMatch(stepAndCheck(game))) {
// nothing
}
这看起来似乎不必要地模糊不清。事实上,对于像这样的玩具示例,它可能是。但是,对于更复杂的问题,这样的技术非常有价值。
答案 4 :(得分:0)
如果你想像你在你的例子中那样用自己的方法保持每一步,你几乎无能为力......
如果您使所有这些方法都返回&#34; true&#34;您可以减少代码量。如果满足停止循环的条件......但是如果您计划在顺序上下文中使用这些方法,则可能无法实现。
if (!g.getBeat() || g.getLost()) do {
if (g.wakeUp()) break;
if (g.goToSchool()) break;
...
if (g.sleep()) break;
} while (true);
可能的技巧是在满足停止条件时使这些方法抛出异常。然后你会在循环外捕获该异常。这样你就可以保存if(...)break语句。然而,这不是一个好习惯。
if (!g.getBeat() || g.getLost()) {
try {
do {
g.wakeUp();
g.goToSchool();
...
g.sleep();
} while (true);
} catch (ActivityLoopFinished ex) {
// nothing to do here
}
}