我整个夏天都在学习C#,现在感觉就像我到目前为止做的一个小项目.我决定采用一种基于文本的冒险游戏.
游戏的基本结构将涉及具有多个扇区(或房间).进入房间后,将输出描述并采取一些行动等等; 能够检查,拾取,使用那个房间里的东西; 可能是战斗系统等等.扇区可以连接多达4个其他扇区.
无论如何,在纸上涂写关于如何为此设计代码的想法,我对我的部分代码的结构感到头疼.
我已经决定了一个球员级别,以及一个代表级别/地牢/区域的"级别"级别.这个级别的课程将由许多相互关联的"部门"组成.在任何给定时间,玩家将出现在该级别中的某个特定部门中.
所以这就是混乱:
从逻辑上讲,人们会期望像player.Move(Dir d)
这样的方法这样的方法应该改变关卡对象中的"当前扇区"字段.这意味着类Player需要知道类级别.嗯.并且Level可能必须操纵Player对象(例如,玩家进入房间,被某些东西伏击,从库存中丢失一些东西.)所以现在Level还需要持有对玩家对象的引用?
这感觉不太好; 一切都必须提到其他一切.
在这一点上,我记得从我正在使用的书中读到有关代表的内容.虽然我知道C++中的函数指针,但有关代表的章节中提供了一些带有"基于事件"编程观点的例子,我对此并没有多少启示.
这给了我设计类的想法如下:
玩家:
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...
}
这是一个好的方法吗?
如果代表章节没有按原样呈现,我就不会想到使用这样的"事件".那么在不使用回调的情况下实现它的好方法是什么?
我习惯于发表非常详细的帖子......抱歉v__v
那么"游戏"类可以容纳大部分信息,如播放器和当前房间.对于诸如移动玩家之类的操作,游戏类可以基于房间的等级地图将玩家移动到不同的房间.
游戏类将管理游戏的各个组件之间的所有交互.
将事件用于此类事件会带来事件变得混乱的危险.如果你不小心,你最终会发现事件相互关闭并且溢出你的堆栈,这将导致标志在特殊情况下关闭事件,以及一个不太容易理解的程序.
UDPATE:
为了使代码更易于管理,您可以将主类之间的一些交互建模为类本身,例如Fight类.使用接口可以使主类执行某些交互.(请注意,我已经冒昧地发明了一些你可能不想要的东西).
例如:
// 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方法这样的东西,你会有许多必须互相了解的类.这是因为移动既不属于玩家也不属于房间 - 移动会相互影响两个对象.通过对主要对象之间的"交互"进行建模,可以避免许多依赖关系.