首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >游戏设计:组织对象数组

游戏设计:组织对象数组
EN

Stack Overflow用户
提问于 2017-03-18 08:42:32
回答 1查看 145关注 0票数 0

为了学习Java,我正在制作一个经典的“太空飞行”2d游戏。除了玩家的目标之外,还有许多敌人/障碍物(食腐动物、猎人、彗星、小行星),每个人都有自己的类,扩展了一个GameObject类。由于可能有几个拾荒者,彗星等,这些都存储在数组。然而,由于每个物体都可以相互作用,所以有很多循环和重复的代码,例如每个外星根据彗星排列列表中的物体、小行星阵列列表等进行交互。

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

代码语言:javascript
复制
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类)

代码语言:javascript
复制
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);
    }
...
}

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

代码语言:javascript
复制
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对象的列表,然后跟踪它们的类类型并进行相应的更新。这是一个更好的方法,还是谁能指出我的正确方向?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-18 09:20:13

是的有更好的方法。

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

例如,如果某些物体按其当前速度移动,并可能与其他物体发生碰撞,则可能存在一个接口:

代码语言:javascript
复制
public interface Moving {
    void move();
    boolean hasCollided(Shape shape);
    void handleCollision(Collision collision);
}

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

代码语言:javascript
复制
movingObjects.forEach(Moving::move);

在它的update方法。

要处理移动后的冲突,您可能有以下内容:

代码语言:javascript
复制
List<Collision> collisions = getAllCollisions(movingObjects);
for (Collision collision: collisions) {
    for (Moving element: collision.getCollidingObjects) {
        element.handleCollision(collision);
    }
}

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

代码语言:javascript
复制
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);
    }
}

然后,您的world对象可以将它们的移动行为委托给该类:

代码语言:javascript
复制
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());
    }
}

这似乎是一个不必要的间接,但经验表明,这是值得的长期。有关更多详细信息,请参阅委托模式

如果每个对象的运动不同,您可以有几个代表(例如,一些受重力影响,一些由人工智能控制),或者一个类可以在其move中应用多个委托(例如重力和惯性),或者一个类可以在其行为唯一的情况下实现自己的move。所有这一切都可能发生,而不需要World就知道对象的类正在调用move

作为一般规则,尽量避免使用extends来继承超类的行为。您的结构猎人扩展全国人民代表大会扩展GameObject将是方便的,直到你意识到你也希望猎人扩展敌人或AIControlled或其他东西。艰难的经验表明,OO编码器最初看起来是明智和优雅的层次结构,但随着添加更复杂的功能,它们变得难以管理。

为了更进一步,隐藏那些对象实现World中哪些行为接口的所有细节,您可能想看看访客模式。这将允许世界对象作为一个移动者访问所有游戏对象,然后作为一个AIAgent,然后作为一个用户控制的对象等等,而不必知道他们在访问期间做了什么(或者他们做了什么)。如果应用得很好的话,它是非常强大的,但它需要一些习惯。

最后,游戏编写人员使用了一种非常常见的架构模式,称为实体组件系统。如果您只是在学习Java,我暂时会忽略这一点,但是如果您成为了一个严肃的游戏开发人员,您可能会发现它比我前面描述的体系结构有所改进。

我显然忽略了这个例子中的很多细节(比如ShapeCirclePositionVelocityCollision等的定义)。但这是一般的想法。这里面有很多东西,值得找一本关于面向对象设计的书或教程来深入研究。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42872235

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档