4

我目前正在创建一个简单的基于控制台的游戏,其中玩家可以在不同的房间之间移动,拿起和使用物品,以及吃东西。在游戏的当前状态下,就是这样。

我需要帮助的是:

为我的游戏创建一个好的“事件”类。我希望它的工作方式是每个项目和房间都应该能够与一个事件相关联。

由于我是新手,因此我将不胜感激与此类程序相关的任何阅读材料,或关于如何最好地考虑以下几点来设置我的课程的建议,或者只是如何攻击这种程序的问题(即难以决定如何设置课程)

我希望能够创建不同类型的事件,例如:

  • 输出一些文字,然后问玩家一个问题。如果玩家给出了正确的答案,就做点什么。

  • 输出一些文本,然后从玩家的物品栏中移除一个物品,然后将玩家移动到另一个房间。

我试图避免的事情:

  • 整个游戏的重点是练习良好的类设计,因此诸如责任驱动设计、内聚和耦合等方面是重要的方面。因此,我希望它尽可能简单、可重用和独立。

  • 必须对每个事件进行硬编码,以便项目或房间只需调用 Event 类中的特定方法。

我此刻在想什么:

创建一些子类,以便我可以使用例如创建新事件(并将它们关联): itemObject.setEvent(new Event(new Question("introText", "outroText", "correctAnswer")));

如果需要更多信息,请告诉我!谢谢!

4

4 回答 4

2

我会考虑的一件事是将输入文本的解析和输出文本的生成与底层域模型分开。您的问题似乎将两者混合在一起,而我会将问题的文本部分视为表示层。

例如,您的域可能包含以下接口:

public enum Action { HIT, TALK_TO, EAT, USE };

public interface GameEntity {
  /**
   * Performs the specified action on this GameEntity, passing in zero or
   * more other GameEntity instances as parameters.
   */
  void applyAction(Action action, GameEntity... params);    
}

public interface Item extends GameEntity { }
public interface Person extends GameEntity { }

此外,您可以定义一个 TextParser 类,该类将处理输入字符串并对域层进行结果调用,或者返回默认响应:“我不明白。”。例如,输入短语“use key on door”将导致方法调用:

key.applyAction(Action.USE, door);
于 2010-11-23T17:59:03.687 回答
2

Game Programming Gems 书籍很棒……虽然有点贵。

您可能可以在GameDev 的文章列表中找到一两篇相关文章,并且可能在他们的论坛中埋藏了一些好东西

至于 Event 类,您几乎肯定想要一个带有一些子类(MoveEvent、InventoryEvent 等)的基类。如果你真的想避免硬编码,你应该在数据文件中定义你的游戏。房间、物品和活动……以及您以后添加的任何其他内容。您用来定义事物的格式完全取决于您。我推荐一些能给你实践经验的东西,因为这是一个学习练习:例如一个你没有使用过的 XML 解析器。不是最有效的解析格式,但这是一个控制台游戏,所以这不是一个问题。

我对 Event 子类的一个建议是可以将其他事件链接在一起。界面不会改变,它允许您执行诸如“将其添加到玩家的物品栏中,将其拿走,然后将它们移至此处”之类的操作。

于 2010-11-23T18:10:50.733 回答
2

当谈到事件时,我们会想到观察者模式。您可以认为您的游戏由多个状态机在内部呈现(您也可以在 Wikipedia 上查找,由于是 SO 新手,我无法自己添加第二个链接)。从一个阶段到另一个阶段的每次转换都是一个事件,可以传达给该事件的注册观察者。

例如:

USE KEY ON LOCK:触发拔出钥匙和开门;隐含地“级联”到下一个事件而无需额外的用户交互(开门):触发房间有额外的出口等。

于 2010-11-23T18:19:57.263 回答
1

我最近实现了类似于你所描述的东西。我首先创建了一个具有“发布”和“订阅”方法的 EventManager 类。当系统启动时,它会扫描所有加载的程序集(库)以查找实现 IEventListener 接口的类:

/// <summary>
/// A class that intends to listen for specific events to be published by an
/// event manager.
/// <see cref="EventManager"/>
/// </summary>
public interface IEventListener
{
    /// <summary>
    /// Subscribes to the event types that this listener wishes to listen for.
    /// </summary>
    /// <param name="eventManager"></param>
    void RegisterSubscriptions(EventManager eventManager);
}

...并在每个人上调用 RegisterSubscriptions 方法。(只有一个 EventManager 实例可以在任何地方使用;我使用依赖注入将其绑定为单例实例。)

RegisterSubscriptions 将简单地为给定类打算处理的每个事件类型和处理程序调用订阅方法。(我使用的是 .NET,因此事件和处理程序更容易使用,但您可以使用匿名子类在 Java 中做同样的事情。)

一个典型的事件可能类似于 RoomEntered,与此事件相关的参数将包括房间 ID 以及可能关于房间的一些其他属性。游戏引擎在用户进入房间时发布此事件,为该房间提供适当的事件参数,然后 EventManager 类负责调用已订阅该事件类型的每个处理程序。此事件的一个处理程序可能是“HandleEnterRoomWithMonsters”,它检查房间是否有怪物,并相应地执行操作。

这总体上有意义吗?您对这种方法有任何疑问吗?

于 2010-11-23T18:09:35.413 回答