Jeo, у меня такая же фигня была, когда срачи на форумах устраивал, ужасающий аргумент против оппонента придумывается только тогда, когда админы уже давнр забыли про закрытую тему. А просчитывать АБСОЛЮТНО все варианты меня отучили, как ни странно, шахматы. Полчаса продумываешь идеальную комбинацию, а противник думает над совершенно другой комбинации и пара ходов отдают полчаса коту под хвост, а это немало даже для партий, когда каждому по полтора часа выдается. С тех пор действую по обстоятельствам, и нормально получается
дык Ваш "бизнес" - купи - продай? В чем изюминка?!
В том, что покупаем картошку на деньги родителей, продаем ее втридорога скупщику, получаем много денег, талдычим всем, что бизнес это тяжело, а все, кроме себя любимого, лентяи и бездельники, лол.
Здравствуйте! Хочу представить вам свой первый движок для создания 2D игр. В нем можно рисовать текст и картинки, и многое другое
Что это такое? WaterLemon2D Engine – open-source движок для создания 2D игр на C++, написанный мной с использованием DirectX11. Список того, что этот движок поддерживает: отрисовка изображений, управление вводом с мыши и клавиатуры, проигрывание звуков, сеть и прочее. Движок разделяется на подсистемы: 1. Подсистема графики – класс Graphics, отрисовывает картинки и текст с помощью Direct3D. 2. Подсистема ввода – класс Input, перехватывает нажатия клавиш и мыши с помощью DirectInput. 3. Подсистема звуков – класс Sound, проигрывает звуковые файлы с помощью DirectSound. 4. Подсистема времени – класс Time, подсчитывает время и FPS (частоту обновления) с помощью стандартных функций Windows. 5. Подсистема сети – класс Network, осуществляет передачу данных между компьютерами в сети с помощью WinSock.
По каждой из этих подсистем будет небольшой туториал
В папке Tutorials содержатся туториалы по движку, я их копирую сюда.
Это первый туториал по WaterLemon2D, где мы научимся выводить изображения и текст, а также познаем основы этого движка.
Для начала нужно скачать архив с папкой WaterLemon2D, где содержится исходный код движка и WaterLemon2D.lib. Примечание: В движке используется DirectX11, и все проекты я пишу на Visual Studio 2012, движок в том числе писался на нем, поэтому информация о линковке библиотеки внизу подразумевает, что у читателя установлен последний DirectX SDK и Visual Studio какой-нибудь версии. Создаем проект (Файл - Создать проект), выбираем вкладку Visual C++. Выберите «Проект Win32» либо «Консольное приложение Win32». Тип проекта не играет особой роли, но я выбираю «Проект Win32», так как там отсутствует консолька, которая совсем не нужна движку Теперь заходим в «Проект – Свойства проекта» (Либо жмем Alt + F7), в самом верху ставим «Конфигурация – Все конфигурации» заходим в «Свойства конфигурации – Каталоги VC++», добавляем в «Каталоги включения» папку Include из DirectX SDK (у меня такой путь до нее: C:\Program Files\Microsoft DirectX SDK %28June 2010%29\Include), а в «Каталоги библиотек» добавляем папку Lib\x86 из того же SDK. Также не забудьте добавить папки Include и Lib из папки движка В папке движка есть папка Sources, программа ищет содержимое этой папки (шейдеры и текст) при запуске, поэтому эти файлы должны быть в папке с игрой.
Теперь создаем файл .cpp, называем его как-нибудь (например, main.cpp) и начинаем писать в нем код:
У меня есть 2 варианта библиотеки – один для дебажной версии, другой для релизной. Этот код означает, что если при компиляции указана Debug-конфигурация, то подключаем дебажную версию движка, иначе – релизную. Теперь дальше:
Код
#include <WaterLemon2D.h>
Подключаем главный файл движка, который, в свою очередь, подключает другие файлы подсистем. Дальше – объявляем пустые функции GameStart() и GameUpdate():
Код
void GameStart() {
}
void GameUpdate() {
}
Первая функция каждый раз будет вызываться по началу работы приложения, вторая – каждый кадр, пока приложение работает. Пока эти функции пустые. Идем дальше:
Первой строчкой идет объявление главной функции приложения. Но для консольных приложений вместо этой строчки напишите просто int main(); Дальше идет блок try-catch. Что это означает? Если попадется какая-нибудь ошибка (не получилось загрузить звуки, инициализироваться, и прочее), то будет создано исключение WaterLemonException, которое будет обработано (вывод информации об ошибке и прекращение работы). Что означает System::Get()->Run()? Это bool функция, которая ведет весь процесс управления приложением, пока она работает и возвращает true, работает и функция GameUpdate(), а если произойдет закрытие приложения, то блок try-catch просто закончится и приложение возвратит 0, за исключением исключений. Почему я использую такую странную конструкцию – System::Get()->Func(…)? Потому что в движке я реализовал шаблон «Одиночка» (Singleton) для всех важных классов, так как это было для меня удобнее всего. Если хотите узнать, как этот шаблон реализуется, добро пожаловать в Википедию. Теперь переходим к функции GameStart() и пишем в ней: System::Get()->Init(L"DEMO VERSION",1200,750,false); Эта функция инициализирует окно приложения и эта функция обязательно должна быть у любого приложения на этом движке. Первый аргумент функции – заголовок окна. Так как вместо массива символов (char*) для инициализации окна требуется тип LPCWSTR (или const WCHAR*), то перед строкой стоит знак L. Второй и третий аргументы – ширина и высота экрана, четвертый – булева функция, которая говорит, включить полноэкранный режим либо нет.
Переходим к функции GameUpdate():
Код
Graphics::Get()->BeginScene(1.0f, 0.0f, 0.0f); // Красный цвет по шкале RGB Graphics::Get()->EndScene();
Скомпилируйте и запустите проект. Для чего нужны эти функции? Во-первых, важно понимать, как работает отрисовка. Допустим, вы управляете игроком клавишами. Игрок передвигается и каждый кадр рисуется на новой (или прежней) позиции. И тут появляется проблема: если все время рисовать игрока, то после движения игрока останется след из спрайта игрока, так как спрайт игрока постоянно рисуется, а прошлые отрисовки спрайта никуда не деваются. Поэтому каждый кадр сцена очищается в какой-либо цвет (обычно черный, хотя в моем примере очистка идет в красный свет), спрайты рисуются заново и сцену предоставляют на монитор, так что вся отрисовка проходит между этими двумя функциями.
Функция во второй строчке загружает изображение, название файла которого введено в качестве первого аргумента (да, это тоже const WCHAR*), второй и третий аргументы определяют размер рисуемой картинки, а четвертый и пятый аргументы – ее позицию. Функция в третьей строчке – перегруженная, она рисует часть картинки, в то время как предыдущая функция рисует ее полностью. Первые пять аргументов такие же, как в предыдущей функции, последующие два аргумента устанавливают точку, где начинается отрисовывание, и 2 последних аргумента устанавливают точку, где отрисовывание заканчивается, таким образом, отрисуется только часть картинки 60 на 60 пикселей. Примечание: я загружаю картинки формата .dds, что это такое? DDS расшифровывается как Direct Draw Surface, то есть это родной формат DirectX. Но отрисовать можно не только картинки этого формата, но еще PNG, BMP, GIF(Не анимация ), JPG, TIFF и, возможно, еще какие-либо малоиспользуемые форматы, причем прозрачность поддерживается в форматах PNG (только 8-битные картинки), GIF и DDS. Четвертой строчкой рисуется текст «Hello!» в позиции (600,700) белого цвета (1.0,1.0,1.0).
В принципе, это все, что нужно знать для отрисовки графики в WaterLemon2D
Вот список используемых функций класса Input:
Код
bool GetKeyPressed(byte key); // Нажата ли клавиша? bool GetMouseKeyPressed(byte key); // Нажата ли кнопка мыши? POINT GetMouseLocation(); // Получаем позицию мыши
Первая функция возвращает true, если клавиша нажата, и false, если нет. Так как я для системы ввода использовал DirectInput, то в качестве аргумента мы в эту функцию вносим название клавиши, начинающееся на DIK_... (Direct Input Key), например, DIK_A, DIK_Q, DIK_ESCAPE и DIK_RETURN означают соответственно клавиши A, Q, Esc и Enter. Вторая функция возвращает true, если нажата указанная кнопка мыши, и false, если наоборот. В качестве аргумента вносим значение 0 или 1; 0 – левая кнопка мыши, 1 – правая кнопка мыши. Третья функция возвращает позицию мыши как объект POINT. POINT это структура от Microsoft, которая ничего интересного не делает, а только содержит поля x и y. Если мы захотим получить позицию мыши по координате x, то получим ее так: Input::Get()->GetMouseLocation().x
Вот пример – код, который завершает работу приложения по нажатию кнопки Escape.
Код
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { try { System::Get()->Init(L"Game",350,200,false); while(System::Get()->Run() && !Input::Get()->GetKeyPressed(DIK_ESCAPE)); // Будем постоянно вызывать Run(), пока мы не закроем приложение либо не нажмем Escape } catch(WaterLemonException ex) { MessageBox(0,ex.text,L"Error",MB_OK|MB_ICONSTOP); return -1; }
Первая функция загружает звуковой файл filename. Если во втором аргументе указано true, то звук будет воспроизводиться бесконечно, иначе – только один раз. Вторая функция делает то же самое, что и первая, только воспроизводит звук только один раз. Примечание: движок умеет загружать только wave-файлы Третья функция прекращает произведение звукового файла filename, ранее загруженного.
Пример использования:
Код
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { try { System::Get()->Init(L"Game",350,200,false);
Первая функция возвращает частоту обновления кадров. Вторая функция возвращает процент «нагруженности» центрального процессора, может быть, пригодится Примечание: Вторая функция на некоторых компьютерах возвращает всегда 0, так как Windows не позволяет взять эту величину из реестра. Странно. Третья функция возвращает время с начала работы приложения в миллисекундах
В этом туториале мы научимся передавать данные между приложениями, напишем эхо-сервер. Перед началом работы важно понять, как передаются между собой данные, понимать, как работает приложения сервера и клиентов. Я не могу описать взаимоотношения этих приложений в силу ограниченности вводного курса, поэтому за ответом на эти вопросы отсылаю вас в Google или Wikipedia. Для тех, кто что-нибудь смыслит в программировании сетей – сеть в движке основана на архитектуре клиент-сервер с использованием протокола TCP/IP. Все, что делает сервер – регистрирует сокет на компьютере для прослушивания сетей на определенном порте, работая с каждым клиентом по отдельности, а все, что делает клиент – подключается по сети к серверу, используя IP компьютера, где он стоит, и порт, который он использует. Самое важное, что надо понимать – клиент и сервер рассылают друг другу массивы символов, причем клиент может их отослать только серверу, а сервер – всем своим клиентам. Примечание: по правде говоря, это не так для приложений клиент-клиент, где приложение одновременно и сервер, и клиент, но движок не работает с такой архитектурой. Сеть в движке представляет класс Network. Вот его функции:
// Клиент void Connect(char* ip); void Receive(char* buff, int size); void Send(char* buff, int size); void SetReceiveHandle(void (*func)());
// Сервер void BindAndListen(); void SetClientHandle(void (*func)(int)); void Receive(int number, char* buff, int size); void Send(int number, char* buff, int size); int GetClientCount();
Функция Init инициализирует WinSock, используя указанный порт. Также в качестве второго аргумента нужно передать true, если приложение асинхронное, и false, если оно синхронное. Дело в том, что функции в WinSock, которые принимают данные, останавливают работу приложения до тех пор, пока данные не придут. Этот подход нормален для крестиков-ноликов, но в остальных случаях этот подход не оправдан, так как вместе с приемом данных следует рисовать графику, проигрывать звуки и делать прочие вещи. Поэтому, если вы пишете клиент, вам нужно писать true, а если сервер – false. Функция Close чистит ресурсы, созданные при работе с WinSock. Теперь функции клиента. Connect() создает связь с сервером, если он есть на компьютере с указанным IP. Receive() сохраняет данные в массиве символов, причем данные размером не больше size (примечание – один символ занимает один байт). Send() отправляет данные из массива символов, отправляется кол-во байтов не больше size. SetReceiveHandle() принимает функцию, которая будет вызываться каждый раз, когда поступили данные (таким образом, в той функции Receive() проходит почти мгновенно, без ожидания, так как данные уже «стучатся в окошко»). Позже я на примере покажу подробнее, как это должно работать. Функции сервера. BindAndListen() заставляет сервер принимать клиентов. Эта функция (в основном потоке) продолжается бесконечно, пока сервер не закроют либо не произойдет что-нибудь страшное. SetClientHandle() принимает функцию, в котором обрабатывается клиент. Когда к серверу подключается клиент, для него создается отдельный поток, внутри которого выполняется эта функция. Receive() и Send() выполняют то же самое, что у клиента, но используя номер клиента. «Что-то?» Дело в том, что основной объект WinSock – сокет, который служит для передачи данных. Так вот, у клиента сокет один для связи с клиентом, и поэтому заранее известно, по какому сокету следует отправлять и принимать данные, а у сервера их несколько – один для прослушивания клиентов, а остальные – для клиентов, которые записаны в список. Когда создается новый сокет клиента, он заносится в список, а функции отправляется индекс сокета клиента в списке, по которому отправляются и принимаются данные. Вы увидите в примере, как это делается. Последняя функция – GetClientCount() – возвращает количество клиентов.
Сейчас мы напишем эхо – сервер. Этот сервер принимает данные от клиента и сразу же отправляет их назад. Клиентом будет отдельное приложение. Код сервера:
Izaron, при чём тут вообще Managed DirectX? Он устарел ещё с приходом XNA. Если хочется писать под DirectX, то можно взять SharpDX.
Все равно как-то не айс брать полудохлые врапперы, можно хотя бы создать DLL со своими функциями и использовать двигло на С# через DLL написанные на С++, но это еще больше не айс, лучше тогда уж чисто под крестами писать
Хм, помню, какой ужас творился в моей голове, когда после ГМЛ открыл учебник по C#.
Лично у меня программерский путь такой:
Паскаль -> GML -> C# (до уровня Hello, world!) -> C++ -> C# (как скриптование к Unity3D) -> C++, на котором я до сих пор программирую. Шарп нравится мне чуточку лучше, чем С++, своим стилем кода, например,
Код
Class::Do() // C++
Код
Class.Do(); // C#
И так:
Код
enum Gun { Pistol, AK47 };
Class::Do(Pistol); // C++
Код
enum Gun { Pistol, AK47 }
Class.Do(Gun.Pistol); // C#
На шарпе не пишут серьезные игры или движки, т.к. Managed DirectX мертв, а остальные фреймворки/врапперы малоизвестны
В Valve пожалуюсь на незаконное использование образов
Зависть это плохо. А вообще, везде такое есть, на курортах устраивают аттракционы Angry Birds, типа попади птицей в свинью, и никого не колышет, что нарушаются права
Все ясно же - родной город - не знаю где, дикий запад - США, лес - Албания походу, болота - Белоруссия, океан наверняка Атлантический, зимние горы - Альпы (Швейцария/Австрия), облака - 0_0
Вот что бывает с ГГ, если они пяти классов не оканчивали ._.
2. Абсолютно неиграбельная игра, по сути. Баги и ужаснейший быдлокод, просто нет слов.
Цитата (Alexis-63)
Баги и ужаснейший быдлокод, просто нет слов.
Цитата (Alexis-63)
ужаснейший быдлокод
ШТАШТА??? Да где ты его взял
Цитата (Alexis-63)
IG_gamer, Да кому нужна твоя игра, школьник?
Ага, да кому вообще такие игры нужны, как ГТА и Батлфилд? "Я" едино и неделимо, а остальные суть дым мироздания, лол ю.
Цитата (Alexis-63)
Причём если бы у тебя проглядывался хоть какой-то стиль, то я бы закрыл на это глаза, ведь бесплатную графику можно подобрать так, чтобы выглядело ок-ок.
Нормальный стиль, все скачано из одной игры, лол[2]
Цитата (Alexis-63)
Полнейшее отсутствие идеи, концепция игры просто дерьмовая
Ну концепции и идей чуть больше или равно, как в мортал комбате
Цитата (Alexis-63)
Дерьмовое и отпугивающее оформление.
По оформлению игра заткнет за пояс многие игры
Цитата (Alexis-63)
Банальнейшее название, выдающее фантазию ребёнка с двумя интеллект-поинтами.
Не в названии дело, не на название я смотрю, играя в игру
Диагноз: патологическая неприязнь к аффтару темы и игры, выражающаяся в необъективном суждении об его творениях.
Не люблю игру Karos. Два года назад в нее играл весь мой класс (я поиграл и мне не понравилось, к тому же тормозило), потом это увлечение у всех прошло, а мой лучший на тот момент друг только и делал, что играл в карос, да хвалился, что играет с 2 по 10 часов дня, пока родаки на работе. Он и раньше так себе учился, а сейчас вообще скатился. Даже самые упоротые двоечники полгода назад ржали над тем, что он написал: "параллельные прямые - это те, которые пересекаются". А ведь еще за 2 года до этого мы вместе играли в Spore и даже делали игры на Game Maker.
P.S. Сейчас он играет не в Карос, а в WoT и иже с ними, не берусь рассуждать об этих играх даже в мыслях, так как я в них не играл и они мне неинтересны в принципе (а до лета у меня был ноут с очень низкой оперативой и с экраном чуть больше планшета, лол), но грустно видеть, что кто-то много играет и ничего в этой жизни не меняется у них, а некоторые ради игры бросают учебу и друзей. Andarky, опередил прям на 10 минут
Добавлено (20.08.2013, 11:40) --------------------------------------------- Он еще и школу хочет бросить после 9 класса, даде не знает, на кого пойдет