gpt4 book ai didi

java - 游戏设计: organizing object arraylists

转载 作者:行者123 更新时间:2023-12-02 02:57:26 26 4
gpt4 key购买 nike

为了学习 Java,我正在制作一个经典的“太空飞行”2d 游戏。除了玩家对象之外,还存在许多敌人/障碍物(拾荒者、猎人、 cometd 、小行星),每个敌人/障碍物都有自己的扩展 GameObject 类的类。由于可能有多个拾荒者、 cometd 等,因此它们存储在数组列表中。然而,由于每个对象都可以相互交互,因此存在大量循环和重复代码,例如每个外星人根据 cometd 数组列表、小行星数组列表等中的对象进行交互。

在我的游戏更新功能中,我有:

public void update() {

ArrayList<Rock> rockList = rock.getRockList();
ArrayList<Scavenger> scavengerList = scavenger.getScavengerList();
ArrayList<Hunter> hunterList = hunter.getHunterList();
....
npc.update(player, scavengerList, hunterList, rockList);
...

}

在我的 NPC 类中(它扩展了 GameObject 类)

public void update(Player player, ArrayList<Scavenger> scavengerList, ArrayList<Hunter> hunterList, ArrayList<Rock> rockList) {

for(int i = 0; i < scavengerList.size(); i++) {
scavengerList.get(i).update(player,scavengerList, ,hunterList rockList);
}
for(int i = 0; i < hunterList.size(); i++) {
hunterList.get(i).update(player,scavengerList, hunterList, rockList);
}
...
}

最后,我的清道夫类、猎人类等中有一个更新函数,例如

public class Hunter extends NPC{
...
public void update(Player player,ArrayList<Scavenger> scavengerList, ArrayList<Hunter> hunterList, ArrayList<Rock> rockList) {
"update all hunter objects according to the player, scavengers, rocks etc"
}

这种方法似乎相当麻烦,并且随着创建更多类,需要解析和循环的数字或数组列表变得失控。谁能推荐一种更好的方法来做到这一点?我想最明显的方法是拥有一个包含所有 NPC 对象的列表,然后跟踪它们的类类型并进行相应更新。这是更好的方法吗?或者有人可以指出我正确的方向吗?

最佳答案

是的,有更好的方法。

对于游戏中的每种类型的对象,计算出它需要展示的一组行为/特征。这些行为应该定义为接口(interface)。然后,处理行为/特征的代码可以使用该接口(interface),而无需了解有关实际类的任何信息。

例如,如果某些对象根据其当前速度每圈移动并且可能与其他对象发生碰撞,则可能存在一个接口(interface):

public interface Moving {
void move();
boolean hasCollided(Shape shape);
void handleCollision(Collision collision);
}

任何移动的类都将实现这个接口(interface)。 World然后对象可以有 List<Moving> movingObjects然后使用:

movingObjects.forEach(Moving::move);

update方法。

要处理移动后的碰撞,您可能会这样做:

List<Collision> collisions = getAllCollisions(movingObjects);
for (Collision collision: collisions) {
for (Moving element: collision.getCollidingObjects) {
element.handleCollision(collision);
}
}

如果实现该接口(interface)的多个类使用类似的机制来移动自身,那么您应该将该逻辑移动到一个单独的类中:

class Inertia implements Moving {
private Velocity velocity;

@Override
public void move(Shape shape) {
velocity.applyTo(shape);
}

@Override
public void applyForceFrom(Position position) {
velocity.accelerateAwayFrom(position);
}
}

然后,您的世界对象可以将其移动行为委托(delegate)给此类:

class Asteroid implements Moving {
private final Inertia inertia;
private Shape shape = new Circle(radius);

@Override
public void move() {
inertia.move(shape);
}

@Override
public boolean hasCollided(Shape other) {
return this.shape.intersects(other);
}

@Override
public void handleCollision(Collision collision) {
intertia.applyForceFrom(collision.getCentreOfMass());
}
}

这似乎是一种不必要的间接方式,但经验表明,从长远来看这是值得的。请参阅Delegation Pattern了解更多详情。

如果每个对象的运动不同(例如,有些受重力影响,有些受 AI 控制等),则可以有多个委托(delegate),或者一个类可以在其 move 中应用多个委托(delegate)。 (例如重力和惯性)或者一个类可以实现自己的 move如果它的行为是独特的。所有这一切都可以在没有World的情况下发生需要了解有关对象类的任何信息正在调用 move上。

作为一般规则,尽量避免使用 extends目的是从父类(super class)继承行为。你的 Hunter 扩展 NPC 扩展 GameObject 的结构将会很方便,直到你意识到你还希望 Hunter 扩展 Enemy 或 AIControlled 或其他东西。艰苦的经验向面向对象的编码人员表明,这些类型的层次结构最初看起来明智且优雅,但随着添加更复杂的功能而变得难以管理。

更进一步,隐藏哪些对象实现哪些行为接口(interface)的所有详细信息 World您可能想查看Visitor Pattern 。这将允许世界对象作为移动者、然后作为 AIAgent、然后作为用户控制对象等访问所有游戏对象,而无需知道它们在访问期间做了什么(或者它们是否做了任何事情)。如果应用得当,它会非常强大,但需要一些时间来适应。

最后,游戏编写者使用了一种非常常见的架构模式,称为 Entity Component System 。如果您刚刚学习 Java,我会暂时忽略这一点,但如果您成为一名认真的游戏开发人员,您可能会发现它比我上面描述的架构有所改进。

我显然在示例中遗漏了很多细节(例如 ShapeCirclePositionVelocityCollision 等的定义),但这就是总体思路。还有很多内容,值得寻找一本有关面向对象设计的书籍或教程来更深入地了解。

关于java - 游戏设计: organizing object arraylists,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42872235/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com