假设我有一个Player
课程。它有一个Move
方法,它接受一个方向参数,一个ChangePosition
方法,它接受两个整数,一个Disappear
void方法,以及其他方法。
我想允许用户(可能使用listbox)能够将一些方法添加到Player对象的行为中。例如,他们可以选择让它向右移动然后向下移动然后消失。然后,他们选择的方法将被添加到事件中,以便在该事件发生时,他们选择的方法将执行。
以前有人做过这样的事吗?做这个的最好方式是什么? (我13岁,我对设计模式知之甚少)
答案 0 :(得分:2)
首先,您应该将所有游戏逻辑放入一个Engine项目中,使用Engine类,它只负责(处理所有游戏的逻辑并与UI和Framework进行通信[和更低层,如果有的话]是任何])。
其次,您可以拥有一个EngineAction类,它具有枚举EngineActionType(Move,ChangePos,Disappear,...)和其他属性。一般的想法是:
有一个枚举来保存类型:
public enum EngineActionType
{
Move,
ChangePos,
Disappear,
...
}
创建一个抽象类,以逻辑方式对所有引擎操作类进行分组,并使用公共Type属性添加它们:
public abstract class EngineAction
{
public readonly EngineActionType Type;
protected EngineAction(EngineActionType type)
{
this.Type = type;
}
}
为每个引擎操作创建一个类,该操作将所有必需参数保存为属性。它应该派生自EngineAction并将适当的EngineActionType发送到基础构造函数:
public class EngineActionMove : EngineAction
{
public int XDelta;
public int YDelta;
public EngineActionMove() : base(EngineActionType.Move)
{
}
}
public class EngineActionChangePos : EngineAction
{
...
}
...
毕竟,你可以把这些对象放在一个列表中,就像用户订购一样,然后迭代它,根据它们的类型逐个执行:
foreach (EngineAction action in actionsToDo)
{
switch (action.Type)
{
case EngineActionType.Move:
EngineActionMove mvAction = (EngineActionMove)action;
// Example:
player.Position = player.Position.Offset(mvAction.XDelta,
mvAction.YDelta);
break;
case EngineActionType.ChangePos:
EngineActionChangePos cpAction = (EngineActionChangePos)action;
// Example:
player.Position = new Point(cpAction.X, cpAction.Y);
break;
case EngineActionType.Disappear:
// Just make the player disappear,
// because the operation needs no parameters
player.Disappear();
break;
case ...:
default:
// maybe throw an error here, to find errors during development
// it helps you find non-handled action types
}
}
进一步提示:UI中的逻辑最少,越好。总是强>
编辑:Charleh的好主意:
public interface IEngineAction
{
void Do(Player target);
}
public class EngineActionMove : IEngineAction
{
public int XDelta;
public int XDelta;
public void Do(Player target)
{
// Example
target.Position = ...
}
}
public class EngineActionDisappear : IEngineAction
{
public void Do(Player target)
{
// Example
target.Visible = false;
}
}
...
添加到列表示例:
var actionsToDo = new List<IEngineAction>();
actionsToDo.Add(new EngineActionDisappear());
actionsToDo.Add(new EngineActionMove { XDelta = 10, YDelta = 20 });
迭代:
foreach (IEngineAction action in actionsToDo)
{
action.Do(player);
}
答案 1 :(得分:2)
另一种选择是使用Action泛型并只添加您想要的方法,然后您可以在任何特定的玩家对象上调用这些操作。
这只是其他人提出的界面设计理念的替代方案,但你的风格可能更喜欢这种方法。
Action<Player> playerActions = p => {}; //Do Nothing
playerActions += p => { p.Move(3); }; //Move
playerActions += p => { p.ChangePosition(1, 1); }; //Change position
playerActions += p => { p.Disappear(); }; //Disappear
//Invoke Actions
Player player = new Player();
playerActions(player);
//Invoke on another object as well
Player player2 = new Player();
playerActions(player2);
答案 2 :(得分:1)
有很多方法可以做到这一点。一种方法是使用工厂模式和策略模式。
public static class PlayerBuilder
{
public static Player BuildPlayer(BuildDefinition definition)
{
//logic in here to build a player -- pseudo-return value below as an example
var strategy = new PlayerMovementStrategy();
return new Player(strategy);
}
}
您的BuildDefinition
课程可以根据您的用户选择进行构建。听起来他们不能只添加任何内容,而是从预定义选项列表中进行选择。根据您的UI选择创建适当的策略。
abstract class MovementStrategy
{
public abstract void Move();
public abstract void ChangePosition(Direction d);
}
class PlayerMovementStrategy
{
public override void Move()
{
//move
}
public override void ChangePosition(Direction d)
{
//change position
}
}
abstract class VisibilityStrategy
{
public abstract void Disappear();
}
class PlayerVisibilityStrategy
{
public void Disappear()
{
//poof
}
}
class Player
{
private readonly PlayerMovementStrategy movement;
private readonly PlayerVisibilityStrategy visibility;
public Player(PlayerMovementStrategy movement, PlayerVisibilityStrategy visibility)
{
this.movement = movement;
this.visibility = visibility;
}
public void Disappear()
{
visibility.Disappear();
}
public void Move(Direction d)
{
movement.Move(d);
}
}