程序设计帮助

4
我正在创建一个简单的基于控制台的游戏,玩家可以在不同的房间之间移动,拾取和使用物品以及进食。目前游戏只有这些功能。
我需要帮助创建一个好的“事件”类来实现以下目标:每个物品和房间都应该能够与一个事件相关联。
由于我是新手,我希望能够阅读相关的资料或建议,以便更好地设置我的类考虑以下几点,或者如何解决这种问题(即无法决定如何设置类)。
我想要能够创建不同类型的事件,例如:
- 输出一些文本,然后问玩家一个问题。如果玩家给出正确答案,则执行某些操作。 - 输出一些文本,然后从玩家的库存中删除一个物品,然后将玩家移动到另一个房间。
我试图避免以下情况:
- 游戏的整个重点是练习良好的类设计,因此责任驱动设计、内聚性和耦合度等方面是重要的。因此,我希望它尽可能简单、可重用和独立。 - 必须硬编码每个事件,使得物品或房间仅调用事件类中的特定方法。
我目前的想法是创建一些子类,以便例如使用以下方式创建新事件(并将其关联):itemObject.setEvent(new Event(new Question("introText", "outroText", "correctAnswer")));
如果需要更多信息,请告诉我!谢谢!

你能具体说明一下你的问题吗? - jzd
3
公平地说,我认为这是一个相当详细的问题。 - Adamski
@Adamski 抱歉,看起来我不知怎么误读了第三段根问题。 - jzd
这是一个3D、2D还是基于控制台的游戏? - a sandwhich
基于控制台,您只需键入文本命令。 - bjrnt
4个回答

2
游戏编程宝典很棒...虽然有点贵。您可以在GameDev的文章列表(https://www.gamedev.net/articles/)中找到相关文章,他们的论坛(https://www.gamedev.net/forums/)中可能会有一些好东西。至于事件类,您几乎肯定希望有一个基类和一些子类(MoveEvent、InventoryEvent等)。如果您真的想避免硬编码,应该使用数据文件来定义游戏。房间、物品和事件...以及您之后添加的任何其他内容。您用来定义事物的格式完全取决于您。我建议您使用一些能够为您提供实际经验的格式,因为这是一项学习练习:例如,您没有使用过的XML解析器。虽然这不是最高效的解析格式,但这是一个控制台游戏,所以这并不是什么问题。我对事件子类的建议之一是可以将其他事件链接在一起的子类。接口不会改变,这使您可以执行诸如“将此添加到玩家的库存中,拿走那个,并将其移动到这里”的操作。

2
谈到事件时,观察者模式 会浮现在脑海中。你可以将你的游戏内部呈现为几个状态机(你也可以在维基百科上查阅此信息,但由于我是 SO 的新用户,无法添加第二个链接)。从一个阶段到另一个阶段的每次转换都是一个事件,可以向注册了该事件的观察者进行通信。
例如:
使用钥匙开锁:触发钥匙的拿走和门的打开;隐含地“级联”到下一个事件,而不需要额外的用户交互(门的打开):触发房间有额外的出口等。

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类来处理输入字符串,并进行相应的领域层调用,否则返回默认响应:“我不理解。” 例如,输入短语“在门上使用钥匙”将导致方法调用:

key.applyAction(Action.USE, door);

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将简单地为给定类打算处理的每个事件类型和处理程序调用Subscribe方法。(我正在使用.NET,因此事件和处理程序更容易使用,但您可以使用匿名子类在Java中执行相同的操作。)

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接