#c#
#c#
Вопрос:
Я пишу простое текстовое приключение и хотел бы иметь главное меню, к которому можно получить доступ в любое время, в то время как любой другой метод выполняется, просто набрав «menu» в консоли
Вот некоторый код, который я написал (извините, если он не очень хорош, я только начинаю изучать), но в этом примере доступ к меню возможен только один раз в начале, в то время как я бы хотел, чтобы он запускался в любое время, когда я набираю «menu», независимо от того, в какой частив данный момент программа запущена
Итак, есть ли какой-нибудь простой и эффективный способ проверить наличие определенного ввода (в данном случае «меню») без копирования метода вставки вызова меню везде?
Любая помощь будет оценена, заранее благодарю
(Это моя предыдущая попытка, которая не сработала, мой новый подход находится в UPDATE1)
class Program
{
static int menuSwitch = 0;
static void Main(string[] args)
{
Console.WriteLine("Welcome to the test program");
string menu = "menu";
string trymenu = Console.ReadLine();
do
{
Console.WriteLine("Main menu");
Console.WriteLine("1.Entry1 n2.Entry2");
Int32.TryParse(Console.ReadLine(), out menuSwitch);
switch (menuSwitch)
{
case 1:
Console.WriteLine("Entry1");
break;
case 2:
Console.WriteLine("Entry2");
break;
default:
Console.WriteLine("Exiting menu");
break;
}
break;
} while (trymenu == menu);
{
Start();
Continue();
End();
}
}
}
UPDATE1
Итак, я немного повозился и сумел заставить его работать по назначению, учитывая советы Алехандро, однако, как я и ожидал, теперь мне приходится вызывать метод Menu после каждого шага (в данном случае консольных сообщений) другого (Start) метода
Мне было интересно, есть ли какой-либо обходной путь для этого или любой другой эффективный метод проверки наличия ввода «меню», поскольку работа с ним кажется чрезмерной и утомительной
class Program
{
static void Main(string[] args)
{
Start();
}
static void Menu()
{
int menuSwitch = 0;
string menu = "menu";
string trymenu = Console.ReadLine();
if (trymenu == menu)
{
Console.WriteLine("Main menu");
Console.WriteLine("1.Entry1 n2.Entry2");
Int32.TryParse(Console.ReadLine(), out menuSwitch);
switch (menuSwitch)
{
case 1:
Console.WriteLine("Entry1");
break;
case 2:
Console.WriteLine("Entry2");
break;
default:
Console.WriteLine("Exiting menu");
break;
}
}
}
static void Start()
{
Console.WriteLine("Welcome to the test program");
Menu();
Console.WriteLine("Type 'menu' to access the main menu");
Menu();
Console.WriteLine("Message1");
Menu();
Console.WriteLine("Message2");
Menu();
Console.WriteLine("Message3");
Menu();
}
}
Комментарии:
1. Когда у вас есть такой повторяющийся шаблон, полезно подумать о его извлечении в отдельном методе, а затем вызывать этот метод везде вместо вашего текущего подхода.
2. Спасибо, удалось заставить его работать, используя ваш подход, проблема с чрезмерным количеством строк «Menu ();», однако, пока остается, вы можете проверить мое обновление, если у вас есть свободное время
Ответ №1:
Вероятно, самым простым способом было бы переместить общий код в метод. Однако вы можете захотеть смоделировать свою игру как конечный автомат.
Это позволяет отделить большую часть контента от игровой логики. Это очень полезно, поскольку позволяет хранить содержимое в некотором файле, который может быть загружен игровым движком. Очень простое состояние может выглядеть примерно так:
public interface IState
{
string Description { get; }
IEnumerable<ITransition> Transitions { get; }
void OnActivated(IState from);
}
public interface ITransition
{
string Command { get; }
IState TargetState { get; }
}
В этой модели команды моделируются как переходы между состояниями. Существует несколько способов получить глобальные переходы:
- Создайте базовый класс, содержащий глобальные переходы, которые должны иметь все состояния
- Добавьте глобальные состояния явно при создании каждого состояния (возможно, с помощью какого-либо вспомогательного метода)
- Встроенные глобальные переходы непосредственно в основной игровой цикл
Примером последней альтернативы может быть что-то вроде этого:
public class Game
{
private readonly IState initialState;
private readonly IEnumerable<ITransition> globalCommands;
private readonly IState exitState;
public Game(IState initialState, IEnumerable<ITransition> globalCommands, IState exitState)
{
this.initialState = initialState;
this.globalCommands = globalCommands;
this.exitState = exitState;
}
private IEnumerable<ITransition> GetTransitions(IState state) => state.Transitions.Concat(globalCommands);
public void Loop()
{
var currentState = initialState;
while (currentState != exitState)
{
Console.WriteLine(currentState.Description);
var transitions = GetTransitions(currentState).ToList();
foreach (var transition in transitions)
{
Console.WriteLine(transition.Command);
}
ITransition nextTransition;
do
{
var command = Console.ReadLine();
nextTransition = transitions.FirstOrDefault(t => t.Command.Equals(command));
} while (nextTransition == null);
nextTransition.TargetState.OnActivated(currentState);
currentState = nextTransition.TargetState;
}
}
}
Одна из сложностей заключается в том, что вы, вероятно, захотите вернуться в любое состояние, которое вы оставили, когда выходите из меню. Одним из способов сделать это может быть сохранение состояния, из которого вы вошли в меню при переходе «выход»:
public class MenuState : IState
{
public string Description { get; }
IEnumerable<ITransition> IState.Transitions => Transitions.Concat(new[] {exit});
public List<ITransition> Transitions { get; } = new List<ITransition>();
private Transition exit;
public virtual void OnActivated(IState from) => exit = new Transition("exit", from);
public MenuState(string description) => Description = description;
}
Комментарии:
1. Спасибо за ваш ответ, отделение игровой логики от содержимого во внешнем файле звучит очень привлекательно! Однако я не думаю, что смог бы справиться с такой задачей на моем текущем уровне, поскольку я никогда раньше не пробовал использовать состояния и интерфейсы, но я готов попробовать это позже, и ваш способ подхода к этому кажется довольно умным и эффективным, поэтому, даже если я не совсем понимаюна данный момент все, я обязательно проверю вашу ссылку, попробую запустить ваш код и попытаюсь узнать, из чего он состоит и как его использовать, еще раз спасибо