1

我正在为游戏编写 AI 对象。

我的目标是优化代码,以便我可以同时处理尽可能多的 AI 进程。

游戏是 2d 物理,所以我已经在处理碰撞处理中的实体编号瓶颈,所以 AI 需要高效。

我正在处理的命令是简单的 ASDF + QE 移动,以及鼠标点击和定位。

我意识到,在实际的键/鼠标上模拟 AI 动作可能不是一个好主意。但我想从这里开始,然后再把它分开。

我决定使用布尔数组来表示命令,如下所示:

//Commands: continue, up, down, left, right, turnQ, turnE, mouse0, mouse1 

boolean[] moveBools = {false, false, false, false, false, false, false, false, false}; 

//The first boolean in the array 'continue' will terminate the loop if its true.

我正在努力解决的是如何将这些数据传递到我的函数中,该函数实际上移动了物理体。我可以简单地在每次游戏迭代中传递一个完整的布尔数组,或者将 /changes/ 从迭代传递到迭代。

这种类型的编程连接到实际的布尔数学,这远远超出了我的知识。我推测我实际上可以创建运算符,就像在 C++ 中所做的那样,让数组状态彼此相减并输出结果。

问题是:鉴于前面的上下文,我怎样才能以最佳速度传递布尔数组?

4

3 回答 3

2
enum Command {
    continuing, up, down, left, right, turnQ, turnE, mouse0, mouse
}

void process(EnumSet<Command> commands) {
    while (commands.isEmpty()) {
        ...
    }
    ...
}

枚举是可能的。EnumSet 像 BitSet 一样是最优的,而 EnumMap 像数组一样。

否则使用位掩码并传递一个 int。int 上的位操作很简单,而且效率稍高一些。

于 2015-11-03T16:23:29.070 回答
1

您所写内容的直接转换是使用BitSet. 它允许您获取位的交集/或、与、和非。你可以做:

BitSet move = new BitSet(9);
move.set(1); // going up
move.set(2); // also going down?

toByteArray()您可以通过流式传输并在接收端重建它来发送这个相对打包的(EG通过网络)new BitSet(inputByteArray)

这些布尔值中有多少会或应该在有效的状态表达式中设置为真?
如果我们猜一个,我们可以做一些更简单的事情。EG 当 continue 为真时,所有其他值都将被忽略,并且(对我来说)上下或左右都为真是没有意义的。尽管在其他状态下同时按下一个或两个鼠标按钮可能是有意义的,并且类似地同时具有向上和向左和 turnQ 之类的功能,如果我们只允许一个状态,则可以简化问题。

IE 如果你代表状态,我会定义一个状态枚举并认为已经完成,有效地将布尔数组等效为单个数字,即枚举的基数。

public enum SingleAiMoves {
    NONE, STOP,
    LEFT, RIGHT,
    UP, DOWN,
    TURN_Q, TURN_E,
    MOUSE1, MOUSE2
}

这一次只允许一个状态。
如果您需要组合多个状态,但只有有效的状态,您可以定义一组逻辑状态,例如:

public enum AiMove {
    //         u/d    l/r    q/e    m1     m2     stop
    STOP      (null,  null,  null,  false, false, true),
    NONE      (null,  null,  null,  false, false, false),
    UP        (true,  null,  null,  false, false, false),
    DOWN      (false, null,  null,  false, false, false),
    LEFT      (null,  true,  null,  false, false, false),
    RIGHT     (null,  false, null,  false, false, false),
    TURN_Q    (null,  null,  true,  false, false, false),
    TURN_E    (null,  null,  false, false, false, false),
    MOUSE_1   (null,  null,  null,  true,  false, false),
    MOUSE_2   (null,  null,  null,  false, true,  false),
    MOUSE_1_2 (null,  null,  null,  true,  true,  false),
    UP_LEFT   (true,  true,  null,  false, false, false),
    DOWN_LEFT (false, true,  null,  false, false, false),
    ... // some 108(?) combinations listed here.... ;

    private final Boolean upDown;
    private final Boolean leftRight;
    private final Boolean turnQE;
    private final boolean mouse1;
    private final boolean mouse2;
    private final boolean stop;

    AiMove(Boolean upDown, Boolean leftRight, Boolean turnQE,
           boolean mouse1, boolean mouse2, boolean stop) {
        this.upDown = upDown;
        this.leftRight = leftRight;
        this.turnQE = turnQE;
        this.mouse1 = mouse1;
        this.mouse2 = mouse2;
        this.stop = stop;
    }
    public boolean isStopped() { return stop; }
    public boolean hasUp() { return Boolean.TRUE.equals(upDown); }
    public boolean hasDown() { return Boolean.FALSE.equals(upDown); }
    public boolean hasLeft() { return Boolean.TRUE.equals(leftRight); }
    public boolean hasRight() { return Boolean.FALSE.equals(leftRight); }
    public boolean hasTurnQ() { return Boolean.TRUE.equals(turnQE); }
    public boolean hasTurnE() { return Boolean.FALSE.equals(turnQE); }
    public boolean hasMouse1() { return mouse1; }
    public boolean hasMouse2() { return mouse2; }
}

我个人认为,如果您走这条路,您可能会考虑表示比某些内部控制器输入更详细的状态。

此外,您还可以使用位标志或掩码,或者看起来更简洁,不花哨,EnumSet<SingleAiMoves>但与上面的枚举不同,并且像您的数组和BitSet,这将允许上下和/或左右的状态存在。

最后,因为我发现在上面的示例中编写所谓的有效组合的枚举乏味且相对不可读,您可以在枚举中使用 BitSet 并阐明枚举的构造。它可能以这种方式使用更多的内存。

public enum AiMove {
    NONE      (),
    UP        (0),
    DOWN      (1),
    LEFT      (2),
    RIGHT     (3),
    TURN_Q    (4),
    TURN_E    (5),
    MOUSE_1   (6),
    MOUSE_2   (7),
    STOP      (8),
    MOUSE_1_2 (MOUSE_1, MOUSE_2),
    UP_LEFT   (UP, LEFT),
    DOWN_LEFT (DOWN, LEFT),
    ... // some 108(?) combinations listed here.... ;

    private final BitSet bitsUDLRQE12S = new BitSet(9);

    AiMove(int index) {
        bitsUDLRQE12S.set(index);
    }

    AiMove(AiMove... moves) {
        for (AiMove move : moves) {
            bitsUDLRQE12S.or(move.getBitSet());
        }
    }

    private BitSet getBitSet() { return bitsUDLRQE12S; }

    public boolean hasUp() { return bitsUDLRQE12S.get(0); }
    public boolean hasDown() { return bitsUDLRQE12S.get(1); }
    public boolean hasLeft() { return bitsUDLRQE12S.get(2); }
    public boolean hasRight() { return bitsUDLRQE12S.get(3); }
    public boolean hasTurnQ() { return bitsUDLRQE12S.get(4); }
    public boolean hasTurnE() { return bitsUDLRQE12S.get(5); }
    public boolean hasMouse1() { return bitsUDLRQE12S.get(6); }
    public boolean hasMouse2() { return bitsUDLRQE12S.get(7); }
    public boolean isStopped() { return bitsUDLRQE12S.get(8); }
}
于 2015-11-03T16:53:27.830 回答
0

Java 通过值传递,但在数组的情况下,它通过值传递对数组的引用——不传递单个元素,只传递对数组的初始引用。

这意味着在传递布尔数组时,您不会传递所有数组,而只是传递引用该数组的值。为了清晰和速度,这可能是您最好的选择。

如果您尝试优化,而不是速度而是内存,那么您可能需要考虑使用 java.util.BitSet。

于 2015-11-03T16:34:43.993 回答