1

假设我有一Player堂课。它有一个Move接收方向参数的ChangePosition方法、一个接收两个整数的方法、一个Disappearvoid 方法等。

我希望允许用户(可能使用列表框)能够将其中一些方法添加到 Player 对象的行为中。例如,他们可以选择让它向右移动,然后向下移动,然后消失。然后他们选择的方法将被添加到一个事件中,这样当该事件发生时,他们选择的方法就会执行。

有没有人做过这样的事情?做这个的最好方式是什么?(我 13 岁,我不太了解设计模式)

4

3 回答 3

2

Another option is to use an Action generic and just add the methods you want and you can then invoke those actions on any particular player object.

This is just an alternative to the inteface design idea proposed by others, but your style may prefer this method.

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);
于 2012-10-07T15:41:43.177 回答
2

首先,您应该将所有游戏逻辑放入一个 Engine 项目中,并带有一个 Engine 类,该类单独负责(处理所有游戏逻辑并与 UI 和 Framework [以及更低层,如果有的话] )。

其次,您可以拥有一个 EngineAction 类,该类具有枚举 EngineActionType(Move、ChangePos、Disappear、...)和其他属性。总体思路是这样的:

有一个枚举来保存类型:

public enum EngineActionType
{
    Move,
    ChangePos,
    Disappear,
    ...
}

创建一个抽象类以对所有引擎操作类进行逻辑分组,并使用公共类型属性添加它们:

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 中的逻辑越少越好。总是。

编辑:查理的好主意:

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);
}
于 2012-10-07T14:48:12.337 回答
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);
     }
}
于 2012-10-07T14:55:56.500 回答