Neofos
@Neofos
Студент, изучаю C#

Как избавиться от визуальных глюков при многопоточности в консоли C#?

Изучаю C# и в целях практики решил создать простую игрульку-бродилку в консоли. Захотелось реализовать возможность стрельбы для персонажа: нажимаешь определённую клавишу, и вылетает пуля:

public static void Controls()
        {
            while (true) // Бесконечное выполнение
            {
                ConsoleKeyInfo pressedKey = Console.ReadKey();
                switch (pressedKey.Key)
                {
                    case ConsoleKey.LeftArrow:
                        MoveLeft();
                        break;
                    case ConsoleKey.RightArrow:
                        MoveRight();
                        break;
                    case ConsoleKey.UpArrow:
                        MoveUp();
                        break;
                    case ConsoleKey.DownArrow:
                        MoveDown();
                        break;
                    case ConsoleKey.Z: // Клавиша для стрельбы
                        new Thread(Fire).Start();
                        break;
                }
            }
        }


Поместил метод стрельбы в новый поток, чтобы игроку ничего не мешало стрелять сколько угодно раз. Сам метод для стрельбы выглядит так:

private static Weapon weapon = new BasicPistol();

        private static void Fire()
        {
            // Рисуем игрока на том же месте, где он был,
            // чтобы вместо него не стояла "я" или "z"
            Console.SetCursorPosition(PosX, PosY);
            Console.Write(appearance);

            if (weapon != null)
            {
                weapon.Fire(PosX + 2, PosY);
            }
        }


Класс оружия, из которого стреляет игрок, выглядит таким образом:

class BasicPistol : Weapon
    {
        protected override double Damage { get; set; } = 10;

        // Кол-во пройденных клеток в секунду.
        protected override int ProjectileSpeed { get; set; } = 200;

        public override void Fire(int posX, int posY)
        {
            bool obstacleIsMet = posX == Map.BorderRight;

            while (obstacleIsMet == false)
            {
                Console.SetCursorPosition(posX, posY);
                Console.Write(Projectile); // Свойство из абстрактного класса Weapon

                // Затираем прежде нарисованную пульку
                Console.SetCursorPosition(posX - 1, posY);
                Console.WriteLine(' ');

                posX++;
                obstacleIsMet = posX == Map.BorderRight;

                Thread.Sleep(1000 / ProjectileSpeed);
            }

            // Стираем пульку при достижении края карты
            Console.SetCursorPosition(posX - 1, posY);
            Console.WriteLine(' ');
        }
    }


Ничего кроме отрисовки полёта пули "стрельба" не умеет, но это сейчас не так важно. Всё нормально, если стрельнуть разок или два:

6096653aa922f361382439.png

Но если прошлая пуля ещё не исчезла, а стреляешь ты много, то возникает такая страшная ситуация:

609665764729d886948359.png

Сам являюсь не очень опытным, поэтому возникает вопрос, можно ли исправить такое, сохранив у игрока возможность стрелять многократно, не дожидаясь, пока предыдущая пуля исчезнет? Буду благодарен за предоставленную помощь
  • Вопрос задан
  • 292 просмотра
Решения вопроса 1
Цикл ввода и отрисовки должен происходит в одном потоке. Нельзя это распараллеливать, в чём вы сейчас и убедились. В отдельные потоки можно в принципе выносить физику и прочие вычисления, которые мало зависят от игрока.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы