Пожалуй нужно начать с небольшой предыстории: сижу я как-то на паре и решили мы с одногруппником поспорить о возможности создания простейших танчиков в консоли (по типу дендивских), но для игры по сети.
Так как компьютерных сетей у нас ещё не было, мне пришлось самой учить всё с нуля. Прочитав, пожалуй, страниц 30 отборного текста и прослушав четыре лекции по этой теме, мне стало очень скучно и лениво слушать это дальше, и я наконец приступила к проекту.
Ну что, все готовы? Начинаем!
Эта статья будет короткой, но информативной (для новичков, как я).
На момент написания статьи я знала всего несколько языков и рассуждала о выборе каждого из них и насколько он подходит для разработки этих самых танчиков. Но опираясь на знания я решила распределить всё так:
C# — клиент (так как самый лёгкий)
Rust — сервер (так как самый безопасный)
Php/html/css/javascript — сайт (который мы ВОЗМОЖНО будем делать)
Часть первая: постановка задачи
Главное что я должна была сделать, дабы доказать правоту — это простые танчики, но я решила сделать универсальный клиент. Как это? — это когда сервер одинаково оптимизирован как и для WinForm, так и для консоли (потому что я хочу хорошие танчики в винформ).
Так что наша задача звучит так: Необходимо разработать три приложения, первое — для WinForm (стандартное окошко виндовс), второе — консольное (эмулятор денди) и третье — сам сервер.
Часть вторая: идеи и огрехи...
Что необходимо делать хорошему приложению? — этот вопрос я задала при проектировании и в моей голове прозвучал ответ:«Быть быстрым».
Что это значит? — то, что нам придётся работать с несколькими потоками приёма/передачи данных. Снаряд не может ждать, пока отрисуется танчик, танк не может ждать пока рисуется стена, чтобы пошевелится.
Мы все знаем как это обидно, когда у тебя падает фпс или не успевает что-то отрисоваться и тебя убивают. Таких ситуаций быть не должно!
Подумав, я решила распределить их именно так:
1-й поток (мэйн) — должен отправлять нажатую клавишу на сервер.
2-й поток должен принимать координаты танков.
3-й координаты стен.
4-й координаты снарядов.
Также желательно было создать чат для общения танкистов во время игры (вдруг в разных кабинетах будем), но это пока не реализовано.
Теперь немного конкретики с потоками, первый должен быть простым отправителем (то есть организовывать минимальны вычисления и отправлять их на сервер), остальные же должны вечно принимать и отрисовывать всё в нашем приложении. В виде кода всё будет примерно так:
static Thread thread_on_frame = new Thread(On_StartFrame);//поток для приёма координат
//танков
static Thread thread_on_frame_wall = new Thread(On_StartFrame_wall);//поток для приёма
//координат стен
static Thread thread_on_frame_puf = new Thread(On_StartFrame_puf);//поток для приёма
//координат и всего прочего связанного с выстрелами
И собственно функции к ним:
static void On_StartFrame() {
//Приём координат танков
}
static void On_StartFrame_wall() {
//Приём координат стен
}
static void On_StartFrame_puf() {
//Приём координат/силы/цвета снарядов
}
//и конечно же функция из нашего мэйна
static void To_key() {
//Передача нажатой клавиши
/*
*
*
* Сюда переводится управления из мэйна при нажатии клавиши.
* Именно под этот метод мы и будем писать дальше код
* Так как под остальные он будет идентичным (будем много копипастить)
*
*/
}
После всего этого у меня возникли несколько вариантов организации данных, для их отправки на сервер, и тут в бой пошли лекции. Выбор стоял великий: или всё организовать в интовских/стринговских переменных и рисовать через них, или создать структуру для данных. Спустя часик гугляния на форумах я остановилась на втором, так как организация данных в виде структуры гораздо легче, да и писать документацию будет удобнее (совет: если есть группы данных, которые схожи по назначению — лучше будет объединить их в структуру, ибо так гораздо легче читать код и искать переменные). Наша новая задача звучит так: создать структуру в которой будут поля отвечающие за нажатую клавишу, координату игрока, угол поворота танка и (для консоли) — позицию последнего символа и желательно какой-то регулятор отрисовки. Для чего нам последнее? — чтобы не использовались координаты с которыми мы работаем (увеличиваем/уменьшаем/отправляем на сервер)
В чём же были ошибки? — спросите меня вы.
Первоначально я начала лезть в дебри http модели (хотелось сделать на http), но спустя количество времени n мне стало ясно что лучше сделать на tcp (и проблем поменьше и с растом возится легче будет).
Мы определились с потоками и с идеей, что же дальше?
А дальше, друзья, будет самое интересное.
Часть третья: наполнение метода Main() и конец первого этапа разработки
Сразу кину код, чтобы нетерпеливые читатели сразу его скопипастили:
public struct player_coor {
public static bool use = false;// показывает, юзаем ли мы сейчас эту стр или нет
public static int x = 2;//пусть по дефолту будет так
public static int y = 2;
public static string dir;//направление (пока что просто по сторонам(left,right...))
public static ConsoleKey key;//нажатая кнопочка
public static int last_x;//последние координаты нашего танчика
public static int last_y;//по ним делаем колайдеры
public static ArrayList colider_x = new ArrayList();//наши колайдеры - дело святое
public static ArrayList colider_y = new ArrayList();//но, возможно, не обязательное
}
public static bool f = true;//это для завершения основного потока
static void Main() {
thread_on_frame.Start();
thread_on_frame_puf.Start();
thread_on_frame_wall.Start();
while (f) {
player_coor.key = Console.ReadKey().Key;
To_key();
}
thread_on_frame.Abort();
thread_on_frame_puf.Abort();
thread_on_frame_wall.Abort();
//thread_background.Abort();
//work.Abort();
f = false;
Это самый простецкий код, но он делает огромную работу: он распоточивает наше приложение.
Небольшое описание потоков: любой поток создаётся через пространство System.Threading. Создаём мы его так же, как и экземпляр класса, но в аргументе потока указываем void функцию.
После создания потока его можно запустить методом .Start() и отключить (вызвать исключение) методом .Abort().
Вот мы написали свой первый «псевдокод» и основные положения/идеи нашего проекта. Первая стадия подошла к концу, а так же подошло к концу наше бездумство, далее мы будем разрабатывать функции и нам придётся попотеть.
Жду ваших пожеланий и идей, да и прибудет с вами сила!
Автор: Алиса Котикова