我整个夏天都在学习 C#,现在我想利用我目前所做的一切来制作一个小项目。我决定开发一种基于文本的冒险游戏。
游戏的基本结构将涉及多个区域(或房间)。进入房间后,将输出描述和一些您可以采取的行动;在那个房间里检查、捡起、使用东西的能力;可能是战斗系统等。一个扇区最多可以连接 4 个其他扇区。
无论如何,在纸上写下关于如何为此设计代码的想法,我正在摸索我的部分代码的结构。
我已经决定了一个玩家类,以及一个委托(delegate)关卡/地牢/区域的“关卡”类。该级别类别将由许多相互关联的“部门”组成。在任何给定时间,玩家都会出现在关卡中的某个特定区域。
所以这里是困惑:
从逻辑上讲,人们会期待一种方法,例如 player.Move(Dir d)
这种方法应该改变关卡对象中的“当前扇区”字段。这意味着 Player 类需要了解 Level 类。嗯。
Level 可能必须操纵 Player 对象(例如,玩家进入房间,被某物伏击,从库存中丢失一些东西。)所以现在 Level还需要持有对 Player 对象的引用吗?
这感觉不太好;一切都必须持有对其他一切的引用。
这时我想起了从我正在使用的书中读到过关于委托(delegate)的内容。虽然我知道 C++ 中的函数指针,但关于委托(delegate)的章节中提供了带有某种“基于事件”编程观点的示例,对此我没有太多启发。
这给了我按如下方式设计类的想法:
玩家:
class Player
{
//...
public delegate void Movement(Dir d); //enum Dir{NORTH, SOUTH, ...}
public event Movement PlayerMoved;
public void Move(Dir d)
{
PlayerMoved(d);
//Other code...
}
}
等级:
class Level
{
private Sector currSector;
private Player p;
//etc etc...
private void OnMove(Dir d)
{
switch (d)
{
case Dir.NORTH:
//change currSector
//other code
break;
//other cases
}
}
public Level(Player p)
{
p.PlayerMoved += OnMove;
currSector = START_SECTOR;
//other code
}
//etc...
}
这样做好吗?
如果委托(delegate)章节不是这样呈现的,我就不会想到使用这样的“事件”。那么在不使用回调的情况下实现这一点的好方法是什么?
我习惯于发布非常详细的帖子......抱歉 v__v
最佳答案
“游戏”类会包含大部分信息,例如玩家和当前房间。对于移动玩家等操作,Game 类可以根据房间的关卡 map 将玩家移动到不同的房间。
游戏类将管理游戏各个组件之间的所有交互。
将事件用于类似这样的事情会带来事件困惑的危险。如果您不小心,您最终会导致事件相互触发并溢出您的堆栈,这将导致在特殊情况下使用标志来关闭事件,以及一个不太容易理解的程序。
更新:
为了使代码更易于管理,您可以将主要类之间的一些交互建模为类本身,例如 Fight 类。使用接口(interface)使您的主类能够执行某些交互。 (请注意,我冒昧地发明了一些您可能不希望在您的游戏中使用的东西)。
例如:
// Supports existance in a room.
interface IExistInRoom { Room GetCurrentRoom(); }
// Supports moving from one room to another.
interface IMoveable : IExistInRoom { void SetCurrentRoom(Room room); }
// Supports being involved in a fight.
interface IFightable
{
Int32 HitPoints { get; set; }
Int32 Skill { get; }
Int32 Luck { get; }
}
// Example class declarations.
class RoomFeature : IExistInRoom
class Player : IMoveable, IFightable
class Monster : IMoveable, IFightable
// I'd proably choose to have this method in Game, as it alters the
// games state over one turn only.
void Move(IMoveable m, Direction d)
{
// TODO: Check whether move is valid, if so perform move by
// setting the player's location.
}
// I'd choose to put a fight in its own class because it might
// last more than one turn, and may contain some complex logic
// and involve player input.
class Fight
{
public Fight(IFightable[] participants)
public void Fight()
{
// TODO: Logic to perform the fight between the participants.
}
}
在您的问题中,您确定了这样一个事实,即如果您在 Player 类中插入诸如 Move 方法之类的东西,那么您将有许多类必须相互了解。这是因为像移动这样的东西既不属于玩家也不属于房间 - 移动会相互影响两个对象。通过对主要对象之间的“交互”进行建模,您可以避免其中的许多依赖性。
关于c# - 关于基于类的文本冒险游戏设计的质疑。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3267638/