Данная курсовая работа направлена на изучение принципов объектно-ориентированного программирования. Создание игровой программы на языке С++, реализующей игру «Змейка», мы постараемся разобраться в различных аспектах создания и использования языка С++.
Объектно-ориентированное программирование представляет собой четь более автоматизированный способ программирования. В основы ООП взято, что программа состоит из групп объектов, часто связанных между собой.
Программа «Змейка» — чисто игровая программа, предназначенная для принесения игровых потребностей пользователя. Для нее потребуется только клавиатура и не большая скорость нажатия на клавиши, так, как только пользователь сможет управлять головой змеи для поедания фруктов и увеличивая своего тела, и игрового счета. Игра прекратиться, как только мы врежемся сами в себя или после победы.
Глава 1. Постановка задач
Предметная область данного проекта – игра «Змейка». Она реализуется с помощью нажатия на клавиши на клавиатуре (передвижение головы змеи и поедание фруктов, при поедании фруктов начисляются баллы и увеличивается длинна змеи).
С чего начать делать игры | Разработка для новичков
Правила игры, следующие: в поле 20х 21 пользователь управляет головой змеи и поедает случайно регенерируемые фрукты. После чего длинна змеи увеличивается и становиться сложнее выполнять повороты чтобы не столкнуться со стеной или со своим же хвостом (при попадании головы змеи или соприкосновении со своим хвостом происходит конец игры). Задача игрока набрать определенное количество фруктов (заданное самим программистом) для победы. В приложение будет приведены изображения всех возможных ситуаций.
Глава 2. Разработка алгоритма
2.1 Описание целей
1) Описываются переменные и константы
2) Выбор начальных координат случайным образом
3) Прорисовка начального положения
4) Генерация на поле яблок случайным образом
5) Проверка: не появилось ли яблоко на черве
6) Управление «Змейкой» с клавиатуры
7) Проверка: не укусила ли змейка сама себя, если укусила, то выводиться информационное окно
8) Проверка: не съела ли змейка яблоко, если съела, то наращиваем ей хвост
9) Перерисовка «Змейки»
В итоге должен получиться вариант игры змейка, который будет содержать:
1) «Змейка», которая может двигаться в ограниченной плоскости.
2) Пользователь, который должен управлять данной «Змейкой».
3) «Змейка» должна увеличиваться в размерах при соприкосновении с фруктом
4) При поедании фрукта будет начислять некоторое количество баллов, заданных программистом для победы.
5) Погибать при столкновении со своим увеличивающимся хвостом.
6) При выходе за границы «Змейка» будет перемещена в противоположную сторону, в которую она зашла.
2.2 Выбор языка программирования
Язык С++ считается в реальное время более все-распространённым и многообещающим языком программирования. К важным свойственным свойствам С++ следует отнести прежде всего сильную помощь объектно-ориентированного подхода к разработке программ и механизма параметризации типов и алгоритмов. Широкий диапазон типов и развитие способности построения пользовательских типов дают возможность правильно отражать особенности предметной области. Развитые схемы преобразования и приведения типов дают возможность гарантировать необходимый компромисс между жесткой типизацией и эффективностью выполнения программ.
С++ считается прямым преемником языка С и практически подключает его как подмножество. Тем самым, С++ имеет полностью отлично зарекомендовавшую себя классическую модель вычисления языка С, в том числе, развитый обще-алгоритмический базис, широкие способности конструирования новых типов и гибких способов работы с памятью, охватываю арифметику над указателями. Если говорить во вкратце, С++ становиться инструментом промышленного программирования в общемировом масштабе.
Наиболее важное понятие языков объектно-ориентированного программирования – это понятие объекта (object). Объект – это логическая единица, которая содержит данные и правила (методы) обработки этих данных. В языке С++ в качестве этих правил обработки выступают функции, т. е. объект в Borland C++ объединяет в себе данные и функции, обрабатывающие эти данные.
Одним из самых ключевых понятий языка С++ считается понятие класса. В языке С++ для того, чтобы классифицировать объект, надо сначала классифицировать его форму с помощью ключевого слова. Всякий объект языка С++ содержит однообразные атрибуты и функциональность с другими объектами того же класса.
За создание собственных классов и поведения объектов этих классов полную ответственность несет сам разработчик программного обеспечения. Работая в некоторой среде, разработчик программного обеспечения получает доступ к обширным библиотекам стандартных классов. Как правило, объект располагается в некотором уникальном состоянии, определяемом текущими значениями его атрибутов.
Глава 3. Кодирование
3.1 Программирование задачи
На данном этапе производим написание кода исходной программы, которая будет находиться в приложение А (Исходный код программы «Змейка»), после постановления задач и составления алгоритма решения, используемый алгоритм в итоге будет записан на выбранном языке программирования (C++).
Структура – это группа данных различны типов и назначения, которая предполагают собой единый информационный элемент [3].
В нашем коде структура и объявление структуры представляет в виде:
struct Zmeja – структура змейки
int PCount; — количество яблок
Любой элемент данных, называемый полем, содержит разное назначение. Одно поле содержит точки, другое количество фруктов. Впрочем, все эти поля связаны между собой, потому что относятся к одному и тому же объекту – змейка. Поскольку в объектах также возможно хранить группы разнотипных данных, то они также содержат структуры.
Различие структуры от класса в том, что в структуре нет закрытых и защищенных членов. Все члены структуры не закрыты.
Вообще объявление структуры аналогично объявлению класса, но вместо ключевого слова class пишется ключевое слово Struct:
Объявление структуры не предполагает создание объекта или же переменной. Объявление – это элементарно описание будущего объекта, в данном случае объекта – змейка. Дабы применить объект определенного класса или же переменную определенного типа их сначала необходимо объявить в качестве объекта этого класса или же переменной этого типа.
3.2 Описание библиотек
1. iostream – заголовочный файл с классами, функциями и переменными для организации ввода- вывода в языке программирования С++. Он включен в стандартную библиотеку С++ [4].
2. time.h – заголовочный файл стандартной библиотеки языка программирования С, содержит типы и функции для работы с датой и временем [4].
3. stdio.h – заголовочный файл стандартной библиотеки языка С, содержит определение макросов, констант и объявления функций, и типов, используемых для различных операций стандартного ввода и вывода [4].
4. windows.h – подключает использования функционала для предоставляемой операционной системой (Windows 95, 98, NT, 2000, XP) [4].
5. conio.h – заголовочный файл, используемый в старых компиляторах, работающих в операционных системах MS-DOS, для создания текстового интерфейса пользователя [4].
6. math.h – заголовочный файл стандартной библиотеки языка программирования С, разработанный для выполнения простых математических операций [4].
7. io.h – это библиотека с определениями низкоуровневых функций ввода и вывода [4].
8. fcntl.h – это библиотека обеспечивает контроль над дескрипторами [4].
9. string.h – заголовочный файл стандартной библиотеки языка С, содержащий функции для работы с нуль – терминированными строками и различными функциями работы с памятью [4].
3.3 Описание функций
Функция разброски яблок.
void PlusJabloko(Game >
1. Процесс int x, y, I;
2. Заводится цикл while, в котором задаем координаты объекта – фрукта.
3. Проверяется объект- фрукт, попало ли оно на объект – змейку.
4. Если объект – фрукт пресекся с объектом – змейка.
5. Если объект – фрукт не пресекся с объектом – змейка, то запоминается позиция объект – фрукт.
6. Переносится курсор в последнею успешную позицию.
7. Присваивается цвет объекту – фрукту.
8. Присваивается изображение объекту – фрукт
Функция старта змейки ее координат и скорость.
void skorostGame(Game >
1. Задается точки – размер объекта – змейка.
2. После создания позиция запоминается.
3. Задается скорость передвижения объекта – змейка.
4. Выполняется рисунок объекта — фрукт.
Функция для выполнения рисунков и движений объектам.
int Move(Game >
1. Вводятся координаты головы объекта – змейка.
2. Вводятся координаты хвоста объекта – змейка.
3. Проверяется следующая точка по направлению объекта – змейка.
4. Проверяется объект – змейка и объект – стена, не пересек ли объект – змейка с объектом – стена.
— При соприкосновении с объектом – стена выводится сообщение «GAME OVER» и производится выход, как видно на рисунке 2.
— При не соприкосновении с объектом – стена игра продолжается.
5. Выполняется проверка объекта – змейка не соприкоснулся он сам собой.
— При соприкосновении выводиться сообщении «GAME OVER» и производится выход, как видно на рисунке 3.
— При не соприкосновении игра продолжается.
6. При поедании объекта – фрукт производиться перекомпиляция объекта – змейка путем увеличения ее длины на одну точку.
7. Появляется новый массив, больший на одну единицу.
8. После съедания объекта – фрукт, закрашивается в цвет объекта – змейка.
9. Происходит закрашивание хвоста объекта – змейка в зеленый цвет.
10. Производиться закрашивание головы объекта – змейка в белый цвет.
Функции управления экранными объектами.
1. Goto X Y () – это функция размещения объекта по координатам х и у.
2. Move (Game g) – это функция, отвечающая за случайный разброс фруктов по полю.
4. skorostGame (Game
//HANDLE hStdout, hStdin;
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
Источник: www.evkova.org
Пишем игровую логику на C#. Часть 1/2
Всем привет. В связи с выходом моей игры SpaceLab на GreenLight я решил начать серию статей о разработке игры на C#/Unity. Она будет основываться на реальном опыте её разработки и немного отличаться от стандартных гайдов для новичков:
Во-первых, я не буду повторять документацию иными словами.
Во-вторых, необходимо знание программирования, чтобы понять о чем я пишу.
К сожалению, эта статья не сможет вам помочь, если вы хотите создать свою казуальную игру используя лишь мышь.
Зато я шаг за шагом расскажу о создании движка, на котором будет работать игровая логика нашей экономической стратегии.
Для тех, кто любит спойлеры или просто хочет почитать код — в конце есть ссылка не репозиторий, где каждый пункт добавлен отдельным коммитом.
Кого заинтересовало узнать, что за игра — внизу есть видео и ссылка на бесплатное скачивание.
Сразу предупрежу — у меня нету цели идеально применить огромное количество паттернов или описать подход к методологии TTD. В статье я стараюсь писать читабельный, поддерживаемый и безбажный код, как он писался бы в жизни. Возможно, людям имеющим огромный скилл в C# и написании игр данная статья покажется очевидной. Тем не менее, вопрос о том, как писать гейм-логику я слышал довольно часто и эта статья прекрасно подойдет и тем, кому интересно написание сервера и тем, кому интересно написание клиента на Unity.
Краткое описание GD, которого мы хотим достичь
1. Игрок управляет кораблем. В корабле можно выстраивать комнаты, в комнатах можно добавлять в слоты модули.
2. Для постройки чего-либо необходимо потратить ресурсы и подождать время.
Через полгода разработки результат должен выглядеть как-то так)
План работы
1. Настраиваем проекты
2. Создаем ядро — базовые сооружения
3. Добавляем и тестируем первые команды — построить строение и модуль
4. Выносим настройки строений и модулей в отдельный файл
5. Добавляем течение времени
6. Добавляем Constructible, строения теперь строятся некоторое время
7. Добавляем ресурсы, для постройки необходимы ресурсы
8. Добавляем цикл производства — модуль потребляет и выдает ресурсы
Статья получилась очень объемной, потому пришлось разделить ее на две части. В данной части мы сделаем первые пять пунктов, а во второй части закончим
1. Настраиваем проекты
На первых порах Unity Editor нам не понадобится — мы пишем ГеймЛогику. Открываем VS и создаем два проекта: GаmeLogic и LogicTests (Unit Tests Project). В первом мы будем писать собственно логику игры на чистом C# не используя namespace Unity, второй будет тестить нашу логику встроенной тест-тулзой. Добавим в GameLogic первый класс Core и напишем первый тест, чтобы проверить нашу связку:
public class Core < public static void Main () <>public Core () <> >
[TestClass] public class Init < [TestMethod] public void TestMethod1 () < Assert.IsInstanceOfType(new Core(), typeof(Core)); >>
2. Создаем ядро — базовые сооружения
Что ж, это указывает, что настроили мы корректно и можно переходить к программированию логики.
Итак, разберемся с нашим гейм-дизайном. У нас есть корабль (Ship), в нем комнаты (Room), в каждую комнату может быть построено строение (Building), а в каждом строении могут быть модули (Module). Конечно, Room и Building можно было бы объединить в одну сущность, но далее такое разделение нам только поможет.
Для всех этих сооружений я создам отдельный namespace Architecture и базовые классы. А так же enum для индексов комнат. Многие вещи, которые мы сейчас делаем — временные и необходимы, чтобы запустить первый тест гейм-логики.
public enum BuildingType
public enum ModuleType
public class Core < public static void Main () <>public readonly Ship Ship = new Ship(); public Core () < Ship.CreateEmptyRooms(); >>
public class Ship < // Временно добавим некоторое количество комнат public readonly int RoomsLimit = 10; private readonly Listrooms = new List(); public IEnumerable Rooms < get < return rooms; >> public void CreateEmptyRooms () < for (var i = 0; i < RoomsLimit; i++) < rooms.Add(new Room(i)); >> public Room GetRoom (int index) < return rooms[index]; >>
public class Room < public readonly int Index; // каждая комната является пристанищем для строения public Building Building < get; set; >public Room (int index) < Index = index; // и по-умолчанию — это пустое строение Building = new Building(BuildingType.Empty); >>
public class Building < // Ограничим количество модулей, которые можно поставить в строение public readonly int ModulesLimit = 10; public readonly BuildingType Type; // Каждый модуль может иметь свою сообтвенную позицию private readonly Dictionarymodules = new Dictionary(); public IEnumerable Modules < get < return modules.Values; >> public Building (BuildingType type) < Type = type; >public Module GetModule (int position) < return modules.ContainsKey(position) ? modules[position] : null; >public void SetModule (int position, Module module) < if (position < 0 || position >= ModulesLimit) < throw new IndexOutOfRangeException( «Position » + position + » is out of range [0:» + ModulesLimit + «]» ); >modules[position] = module; > >
public class Module < public readonly ModuleType Type; public Module (ModuleType type) < Type = type; >>
3. Добавляем и тестируем первые команды — построить строение и модуль
Теперь мы сможем написать первую «фичу» — постройка строения и постройка модуля в нем. Все подобные действия я буду описывать отдельным классом, который будет наследоваться от класса Command:
public abstract class Command < public Core Core < get; private set; >public bool IsValid < get; private set; >public Command Execute (Core core) < Core = core; IsValid = Run(); return this; >protected abstract bool Run (); >
И хотя сейчас даже такая маленькая структура излишня — чуть позже благодаря ей мы прикрутим необходимые нам события. А существование каждого атомарного действия в отдельной команде позволит нам их комбинировать. Напишем наши первые два действия:
public class BuildingConstruct : Command < public readonly Room Room; public readonly Building Building; public BuildingConstruct (Room room, Building building) < Room = room; Building = building; >protected override bool Run () < // Нельзя строить там, где уже что-то есть if (Room.Building.Type != BuildingType.Empty) < return false; >// Нельзя строить пустую комнату if (Building.Type == BuildingType.Empty) < return false; >Room.Building = Building; return true; > >
public class ModuleConstruct : Command < public readonly Building Building; public readonly Module Module; public readonly int Position; public ModuleConstruct (Building building, Module module, int position) < Building = building; Module = module; Position = position; >protected override bool Run () < if (Building.Type == BuildingType.Empty) < return false; >if (Position < 0 || Position >= Building.ModulesLimit) < return false; >if (Building.GetModule(Position) != null) < return false; >Building.SetModule(Position, Module); return true; > >
Пришло время посмотреть, работает ли наш движок. В тестах создаем ядро, пробуем построить комнату, а в нее пытаемся построить модуль. Кроме этого стоит добавить проверку, что нельзя построить то, чего гейм-логика не должна позволять строить:
[TestClass] public class Architecture < [TestMethod] public void CorrectConstruction () < var core = new Core(); var room = core.Ship.GetRoom(0); Assert.AreEqual(BuildingType.Empty, room.Building.Type); Assert.AreEqual(0, room.Building.Modules.Count()); Assert.IsTrue( new BuildingConstruct( room, new Building(BuildingType.PowerPlant) ) .Execute(core) .IsValid ); Assert.AreEqual(BuildingType.PowerPlant, room.Building.Type); Assert.AreEqual(0, room.Building.Modules.Count()); Assert.IsTrue( new ModuleConstruct( room.Building, new Module(ModuleType.Generator), 2 ) .Execute(core) .IsValid ); Assert.AreEqual(BuildingType.PowerPlant, room.Building.Type); Assert.AreEqual(ModuleType.Generator, room.Building.GetModule(2).Type); Assert.AreEqual(1, room.Building.Modules.Count()); >[TestMethod] public void IncorrectConstruction () < var core = new Core(); var room = core.Ship.GetRoom(0); Assert.IsFalse( new BuildingConstruct( room, new Building(BuildingType.Empty) ) .Execute(core) .IsValid ); Assert.IsFalse( new ModuleConstruct( room.Building, new Module(ModuleType.Generator), 2 ) .Execute(core) .IsValid ); new BuildingConstruct( room, new Building(BuildingType.PowerPlant) ) .Execute(core); Assert.IsFalse( new BuildingConstruct( room, new Building(BuildingType.PowerPlant) ) .Execute(core) .IsValid ); Assert.IsFalse( new ModuleConstruct( room.Building, new Module(ModuleType.Generator), 666 ) .Execute(core) .IsValid ); >>
4. Выносим настройки строений и модулей в отдельный файл
К счастью, наши тесты прекрасно проходятся. Теперь нам необходима возможность линейно расширять количество строений и модулей — для этого необходимо сделать следующее:
- Создать конфигурацию для строений и модулей — » class BuildingConfig » и » class ModuleConfig «, именно они будут хранить все настройки наших сооружений.
- Building и Module при создании должны принимать соответствующие настройки
- Сделать фабрику для создания модулей и строений
- Добавить настройки для нескольких строений и модулей
- Адаптировать существующий код под новые входные данные
// Создаем конфиги public class BuildingConfig < public BuildingType Type; // Теперь никаких констант public int ModulesLimit; // Каждое строение может иметь только определенные модули public ModuleType[] AvailableModules; >
public class ModuleConfig
public class Building < // . public readonly BuildingConfig Config; // . // В конструкторе принимаем конфиг, а не индекс public Building (BuildingConfig config) < Type = config.Type; ModulesLimit = config.ModulesLimit; Config = config; >>
public class Module < // . public readonly ModuleConfig Config; // В конструкторе принимаем конфиг, а не индекс public Module (ModuleConfig config) < // . Type = config.Type; Config = config; >>
Как можно понять, теперь наш код нерабочий. Для того, чтобы не таскать каждый раз с собой конфиги создадим фабрику, которая будет выпускать наши сооружения зная только их тип. Я знаю, что название пока слишком общее, но мы всегда с легкостью можем его переименовать благодаря IDE, так же, как и разделить на две фабрики:
public class Factory < public Building ProduceBuilding (BuildingType type) < throw new Exception(«Not implemented yet»); >public Module ProduceModule (ModuleType type) < throw new Exception(«Not implemented yet»); >>
// А также добавим нашу фабрику в ядро: public class Core < // . public readonly Factory Factory = new Factory(); public Core () < // В аргумент метода передаем фабрику Ship.CreateEmptyRooms(Factory); >>
// Корабль теперь принимает фабрику в качестве аргумента: public class Ship < // . public void CreateEmptyRooms (Factory factory) < for (var i = 0; i < RoomsLimit; i++) < rooms.Add(new Room(i, factory.ProduceBuilding(BuildingType.Empty))); >>
// А комната — принимает строение по-умолчанию: public class Room < // . public Room (int index, Building building) < Index = index; Building = building; >>
Сейчас IDE указывает, где мы имеем ошибки — заменим там вызов конструктора на использование фабрики.
// в тестах new Building(Type); // заменяем на core.Factory.ProduceBuilding(Type);
// в тестах new Module(Type); // заменяем на core.Factory.ProduceModule(Type);
И хотя сейчас код корректен — при запуске наших тестов мы словим «Not implemented yet» . Для этого вернемся к нашей фабрике и реализуем несколько строений и модулей.
public class Factory < private readonly Dictionarybuildings = new Dictionary() < < BuildingType.Empty, new BuildingConfig() < Type = BuildingType.Empty >>, < BuildingType.PowerPlant, new BuildingConfig() < Type = BuildingType.PowerPlant, ModulesLimit = 5, AvailableModules = new[]< ModuleType.Generator >>>, < BuildingType.Smeltery, new BuildingConfig() < Type = BuildingType.Smeltery, ModulesLimit = 4, AvailableModules = new[]< ModuleType.Furnace >>>, < BuildingType.Roboport, new BuildingConfig() < Type = BuildingType.Roboport, ModulesLimit = 3, AvailableModules = new[]< ModuleType.Digger, ModuleType.Miner >>> >; private readonly Dictionary modules = new Dictionary() < < ModuleType.Generator, new ModuleConfig() < Type = ModuleType.Generator >>, < ModuleType.Furnace, new ModuleConfig() < Type = ModuleType.Furnace >>, < ModuleType.Digger, new ModuleConfig() < Type = ModuleType.Digger >>, < ModuleType.Miner, new ModuleConfig() < Type = ModuleType.Miner >> >; public Building ProduceBuilding (BuildingType type) < if (!buildings.ContainsKey(type)) < throw new ArgumentException(«Unknown building type: » + type); >return new Building(buildings[type]); > public Module ProduceModule (ModuleType type) < if (!modules.ContainsKey(type)) < throw new ArgumentException(«Unknown module type: » + type); >return new Module(modules[type]); > >
Я сразу добавил несколько строений и модулей, чтобы можно было покрыть тестами.
И сразу скажу — да, хранить все эти настройки в фабрике нету никакого смысла. Они будут лежать отдельно в JSON файлах, по одному на структуру, парсится и передаваться в фабрику. К счастью, у нас движок даже не заметит этого изменения. Ну а пока нам не так критично вынести их в ЖСОНы, как запустить тесты и проверить все ли корректно работает. К счастью, да.
Заодно допишем тесты, что нельзя построить модуль не в той комнате, например, Furnace в PowerPlant.
[TestMethod] public void CantConstructInWrongBuilding ()
Увы, как вы можете догадаться, никто логику проверки не писал. Добавим условие валидации в команду постройки модуля и после этого успешно пройдем тест:
public class ModuleConstruct : Command < // . protected override bool Run () < // . if (!Building.Config.AvailableModules.Contains(Module.Type)) < return false; >// .
Что ж, теперь все корректно. Заодно добавим тесты на корректную работу лимитов и пойдем дальше.
[TestMethod] public void ModulesLimits ()
5. Добавляем течение времени
Компьютеры дискретны. И все игры дискретны. Если говорить просто, то представим, что все игры — пошаговые. У большинства игр шаги пропускаются автоматически и 60 раз в секунду. Такие игры называются риалтайм.
Я понимаю, что это очень грубо, но для реализации гейм-логики довольно удобно представлять, что ваша игра — пошаговая и мыслить такими категориями. А потом уже на клиенте можно запустить tween между двумя состояниями и юзеру будет красиво и игра будет работать быстро. Для начала введем понятие хода:
public class Turns < public int CurrentTurn < get; private set; >internal void NextTurn () < CurrentTurn++; >>
public class Core
А также введем команду, которая позволяет переключать хода. Я сразу добавил команду, которая позволяет переключить несколько ходов — будет довольно удобно во время тестирования. В тестах одним выстрелом покроем сразу двух зайцев.
public class NextTurn : Command < protected override bool Run () < // Именно тут будет вся логика хода Core.Turns.NextTurn(); return true; >>
public class NextTurnCount : Command < public const int Max = 32; public readonly int Count; public NextTurnCount (int count) < Count = count; >protected override bool Run () < if (Count < 0 || Count >Max) < return false; >for (var i = 0; i < Count; i++) < var nextTurn = new NextTurn().Execute(Core); if (!nextTurn.IsValid) return false; >return true; > >
[TestClass] public class Turns < [TestMethod] public void NextTurnsCommand () < var core = new Core(); Assert.AreEqual(0, core.Turns.CurrentTurn); Assert.IsTrue( new NextTurnCount(4) .Execute(core) .IsValid ); Assert.AreEqual(4, core.Turns.CurrentTurn); >>
Забегая далеко вперед напишу, как сделать переключалку скоростей в игру, которая позволит нам запускаться с разной скоростью:
public class TimeWarp < public readonly int Speed_Stop = 0; public readonly int Speed_X1 = 1000; public readonly int Speed_X2 = 500; public readonly int Speed_X5 = 200; public readonly Core Core; private int currentSpeed; public int currentTime < get; private set; >public TimeWarp (Core core) < currentSpeed = Speed_Stop; Core = core; >public void SetSpeed (int speed) < currentSpeed = speed; currentTime = Math.Min(speed, currentTime); >public int GetSpeed () < return currentSpeed; >public bool IsStopped () < return currentSpeed == Speed_Stop; >public void AddTime (int ms) < if (IsStopped()) return; currentTime += ms; // Тут можно написать через // while (currentTime >= currentSpeed) NextTurn // Но зачем запускать каждый кадр больше одного хода? // Даже 20 ходов в секунду будет более чем достаточно if (currentTime < currentSpeed) return; currentTime -= currentSpeed; new NextTurn().Execute(Сore); >>
[TestMethod] public void TimeWarp ()
Теперь в Unity достаточно будет подвесится на любой Update и передавать дельта время в наш TimeWarp:
public TimeComponent : MonoBehaviour < public TimeWarp timeWarp; public void Awake () < timeWarp = . ; // >public void Update () < timeWarp.AddTime( Time.deltaTime ); >>
Продолжение следует.
В следующей статье мы закончим создание работоспособной основы для нашего движка, реализовав следующие пункты:
6. Добавляем Constructible, строения теперь строятся некоторое время
7. Добавляем ресурсы, для постройки необходимы ресурсы
8. Добавляем цикл производства — модуль потребляет и выдает ресурсы
Для тех, кто просто любит код — есть отдельный репозиторий на ГитХаб
Кроме этого, если вас интересуют вопросы по разработке SpaceLab — задавайте, отвечу на них в комментариях или в отдельной статье
Скачать для Windows, Linux, Mac бесплатно и без СМС можно со страницы SpaceLab на GreenLight
Источник: habr.com
Игра на C#
Игра на C# с нуля / Урок #1 – Создание игры на C# WinForms для начинающих
Представляем вам курс по разработке игры на базе языка C# и платформы WinForms. В курсе для начинающих вы с нуля создадите небольшую 2Д игру без использования какого-либо игрового движка.
Видеоурок
Информация про WinForms
Windows Forms является относительно простой платформой для разработки различных приложений под операционную систему Виндовс. На ее основе вы можете строить небольшие проекты, что будут обладать пользовательским интерфейсом, дизайном и функциями.
Помимо приложений вы также можете строить небольшие игры. И тут стоит сказать, что любая игра от приложения в основе своей отличается динамической картинкой. В программах различные действия выполняются только при взаимодействиях с пользователем, в играх действия выполняются автоматически.
В WinForms можно указать объект таймер, что в автоматическом режиме выполняет действия внутри игры. Так вы можете создать автоматическую смену объектов, передвижение игроков и прочие динамические эффекты.
А как же игровые движки?
Для разработки более-менее крупных проектов вам в любом случае понадобиться изучить игровой движок для построения игр. Например, для языка C# есть отличный движок под названием Unity .
Вы можете задать вопрос: «А зачем разрабатывать игры без использования игрового движка?». На самом деле, разработка проектов на чистом C# позволит вам лучше понять всю суть построения проектов. Вы будете лучше понимать как происходит создание игры, из чего оно состоит и какие основные этапы существуют при построении игр. В будущем при поиске работы вы всегда сможете сказать что умеете писать игры без игровых движков, что является приятным бонусом к вашему резюме.
План курса
В ходе курса мы с вами ознакомимся с платформой WinForms и на ее основе научимся создавать простые 2Д игры. Мы разработаем небольшую гоночную игру, где у нас будет основной игрок, машинки противников, сбор монет, экран проигрыша и динамическая смена заднего фона.
Это будет вполне играбельный проект, что будет создан без каких-либо игровых движков. После курса вы сможете создавать свои подобные небольшие игры или же сможете перейти к изучению игровых движков и построению проектов на их основе.
Курсы по C# и Unity разработке
Если вы хотите получить больше информации относительно языка C#, то рекомендуем вам дополнительный курс по этой теме.
На нашем сайте вы можете найти полноценную программу обучения по C# разработке и построению программ на его основе. Ознакомится с программой обучения по С# можно по этой ссылке .
Помимо изучения языка C# вы также можете посмотреть нашу другую программу обучения по разработке игр на базе игрового движка Unity .
Большое задание по курсу
Вам необходимо оформить подписку на сайте, чтобы иметь доступ ко всем большим заданиям. В задание входит методика решения, а также готовый проект с ответом к заданию.
PS: подобные задания доступны при подписке от 1 месяца
Источник: itproger.com