C# c语言中的状态模式#

C# c语言中的状态模式#,c#,state-pattern,C#,State Pattern,我读了一本叫做《游戏编程模式》的书,开始用C#实现其中的一些模式。现在,我正在实现下面的UML类图描述的状态模式 这是我的主要节目。我使用了两个不同的线程,以便不停止键盘用户输入的游戏循环。在hero类中,HandleInput方法调用存储在字段state中的当前状态的HandleInput方法 class Program { private static string key; private static Thread t; private static Hero

我读了一本叫做《游戏编程模式》的书,开始用C#实现其中的一些模式。现在,我正在实现下面的UML类图描述的状态模式

这是我的主要节目。我使用了两个不同的线程,以便不停止键盘用户输入的游戏循环。在hero类中,HandleInput方法调用存储在字段state中的当前状态的HandleInput方法

class Program
{

    private static string key;
    private static Thread t;
    private static Hero hero1;

    public delegate void PressDelegate();
    public static event PressDelegate OnPress;
    static void Main(string[] args)
    {
        // Creating Hero
        hero1 = new Hero("zelda");

        // Subscribing to KeyboardInput Event
        OnPress += KeyboardInputHandler;

        // Game Loop
        t = new Thread(new ThreadStart(KeyboardInput));
        t.Start();
    }
    private static void KeyboardInput()
    {
        while (true)
        {
            key = Console.ReadLine();
            OnPress();
        }

    }
    private static void KeyboardInputHandler()
    {
        hero1.HandleInput(key);
    }
}
}

我的目标是,当用户按空格键时,英雄将其状态更改为JumpingState(假设其默认状态为IDLState),并在1秒后更改回idle(模拟重力效果)。问题是我已经尝试了一些解决方案,比如在IDLState中设置计时器,但是对于每个转换到跳跃状态的状态(例如,一个躲闪状态),我都必须这样做。我还尝试在hero类上使用if语句来实现这一点:(如果state是JumpingState,那么启动计时器,当finish调用SetState(idlstate)时,类似的东西),但我觉得这打破了SetState方法只在状态内部调用,而不在hero上调用的事实


我非常感谢您的帮助:)

通常游戏是在游戏循环中运行的。一个非常简单的可以如下所示:

  • 读取输入
  • 进程输入(移动角色、推进敌人等)
  • 得出结果
  • 该循环通常以或多或少的固定速率进行。这与大多数windows程序不同,windows程序仅在用户提供某种输入或程序具有触发的计时器时运行

    因此,活动状态将在每一帧接收一个更新调用,然后它有机会决定要做什么。州政府通常会检查游戏状态和用户输入,然后根据这些信息决定要做什么

    不必在单独的线程中读取输入,您可以使用该线程检查密钥是否可用,如果可用,则不应阻止

    我用来编程状态机的方式是使用一些输入参数调用当前状态,并返回下一个要使用的状态。可以考虑以下一系列细节:

    • 你应该处理所有的输入吗?每帧仅最后一次输入?仅当帧开始时按下该键时
    • 是否有可能在每帧中多次切换状态?例如,“跳跃”可能会转换为“空闲”,但如果用户按住shift键,则可能会立即转换为“蜷缩”
    • 将“状态”和“过渡”分开是很常见的。这有助于使状态机更加抽象。也就是说,您可以使用OnKeyTransition,将输入键和目标状态作为输入,而不是硬编码英雄应该在每个状态下跳转到空格。然后可以将此转换添加到所有应支持跳跃的状态
    • 在一个游戏中可以有许多不同类型的状态机。一个高级别可能是,如果玩家正在驾驶汽车、步行、驾驶飞机等。较低级别的状态机可能处理动画。第三种可以用于人工智能。所有这些都有不同的需求,因此需要区别对待
    这将是一个非常简单的状态机的例子。我不确定它是否正是你想要的,但我希望它至少能提供一些灵感

    public class State
    {
        public virtual State Update(ConsoleKey? input, TimeSpan deltaTime) => this;
    }
    
    public class IdleState : State
    {
        public override State Update(ConsoleKey? input, TimeSpan deltaTime)
        {
            if (input == ConsoleKey.Spacebar)
            {
                return new JumpingState();
            }
            return base.Update(input, deltaTime);
        }
    }
    
    public class JumpingState : State
    {
        private TimeSpan elapsed = TimeSpan.Zero;
    
        public override State Update(ConsoleKey? input, TimeSpan deltaTime)
        {
            elapsed += deltaTime;
            if (elapsed > TimeSpan.FromSeconds(1))
            {
                return new IdleState();
            }
            return base.Update(input, deltaTime);
        }
    }
    
    public class Game
    {
        static void Main(string[] args)
        {
            var game = new Game();
            game.StartGame();
    
        }
    
        State currentState = new IdleState();
        private TimeSpan frameRate = TimeSpan.FromMilliseconds(30);
    
        public void StartGame()
        {
            Console.WriteLine("Game Started");
            while (true)
            {
    
                var input = GetLastKeypress()?.Key;
                if (input == ConsoleKey.Escape)
                {
                    Console.WriteLine("Game Over");
                    return;
                }
    
                // Update the state 
                var nextState = currentState.Update(input, frameRate);
                if (nextState != currentState)
                {
                    currentState = nextState;
                    Console.WriteLine(currentState.GetType().Name);
                }
                Thread.Sleep(frameRate);
            }
        }
    
        private ConsoleKeyInfo? GetLastKeypress()
        {
            ConsoleKeyInfo? info = null;
            while (Console.KeyAvailable)
            {
                info = Console.ReadKey();
            }
            return info;
        }
    }
    

    可以为所有将转换回跳跃状态的状态创建一个基类,其中包含计时器逻辑我认为回到空闲状态应该只适用于跳跃状态,而不是所有状态?我说的是所有需要这样做的状态-你在问题中说你有不止一个状态需要这样做。否则我不确定问题出在哪里非常感谢你的回答。它确实回答了我提出的问题,还提供了一些gameloop的基本知识。我认为我犯的错误是没有在state类中包含update方法,这样我就可以在其中运行计时器。再次感谢