Методические указания по выполнению лабораторных и практических работ по мдк
Скачать 3.25 Mb.
|
Игровая документация 122 Если вы начинаете разрабатывать серьезный игровой проект – вам понадобится игровая документация. Эта лекция посвящена вопросам разработки такой документации. В частности, мы поговорим о концепт-документе, дизайн-документе и плане разработки игры. В работе над этим материалом использованы образцы документов, рекомендованных компанией 1С для заполнения желающим сотрудничать с ней разработчикам. Актуальные версии образцов документов можно найти на (http://games.1c.ru/4_files/desdocpack.zip). Автор курса выражает признательность Сергею Герасеву – Менеджеру внешней разработки игровых программ 1С (gers@1c.ru) за содействие. План разработки игры План разработки игры – это рабочий документ, который направлен на детализацию некоторых положений, имеющихся в ранее составленных документов и на планирование производства игры. Он может иметь следующую структуру: 1. Анализ рынка 1.1. Целевая аудитория 1.2. Хиты и сравнение 2. Технический анализ 3. Ресурсы проекта 3.1. Персонал 3.2. Оборудование 3.3. Программное обеспечение 3.4. Финансовые ресурсы Риски проекта Календарный план Документ gameproposaltemplate.doc содержит шаблон плана разработки от 1С, документ gameproposal.doc– пример плана разработки. Практическая работа № 1.30. Разработка игрового приложения Цель работы: создание игрового приложения Ход работы Создаем файл main.cpp #include int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { return 0; } Пока что он ничего не делает. Создаем каркас — класс Game Game.h #ifndef _GAME_H_ #define _GAME_H_ class Game { private: bool run; public: Game(); int Execute(); void Exit(); 123 }; #endif Game.cpp #include "Game.h" Game::Game() { run = true; } int Game::Execute() { while(run); return 0; } void Game::Exit() { run = false; } Создаем файл Project.h, он нам очень пригодится в будущем #ifndef _PROJECT_H_ #define _PROJECT_H_ #include #include "Game.h" #endif Изменяем main.cpp #include "Project.h" int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Game game; return game.Execute(); } 1.2. Графика Создаем 2 класса — Graphics для отрисовки графики и Image для отрисовки картинок Graphics.h #ifndef _GRAPHICS_H_ 124 #define _GRAPHICS_H_ #include "Project.h" #include "Image.h" class Image; class Graphics { private: SDL_Surface* Screen; public: Graphics(int width, int height); Image* NewImage(char* file); Image* NewImage(char* file, int r, int g, int b); bool DrawImage(Image* img, int x, int y); bool DrawImage(Image* img, int x, int y, int startX, int startY, int endX, int endY); void Flip(); }; #endif Image.h #ifndef _IMAGE_H #define _IMAGE_H #include "Project.h" class Image { private: SDL_Surface* surf; public: friend class Graphics; int GetWidth(); int GetHeight(); }; #endif Изменяем Project.h #ifndef _PROJECT_H_ #define _PROJECT_H_ #pragma comment(lib,"SDL.lib") #include #include 125 #include "Game.h" #include "Graphics.h" #include "Image.h" #endif SDL_Surface — класс из SDL для хранения информации об картинке Рассмотрим Graphics NewImage — есть 2 варианта загрузки картинки. Первый вариант просто грузит картинку, а второй после этого еще и дает прозрачность картинке. Если у нас красный фон в картинке, то вводим r=255,g=0,b=0 DrawImage — тоже 2 варианта отрисовки картинки. Первый рисует всю картинку целиком, второй только часть картинки. startX, startY — координаты начала части картинки. endX, endY — конечные координаты части картинки. Этот метод рисования применяется, если используются атласы картинок. Вот пример атласа: (изображение взято из веб-ресурса interesnoe.info) Рассмотрим Image Он просто держит свой сурфейс и дает право доступа к своим закрытым членам классу Graphics, а он изменяет сурфейс. По сути, это обертка над SDL_Surface. Также он дает размер картинки Graphics.cpp #include "Graphics.h" Graphics::Graphics(int width, int height) { SDL_Init(SDL_INIT_EVERYTHING); Screen = SDL_SetVideoMode(width,height,32,SDL_HWSURFACE|SDL_DOUBLEBUF); } Image* Graphics::NewImage(char* file) { Image* image = new Image(); image->surf = SDL_DisplayFormat(SDL_LoadBMP(file)); return image; } 126 Image* Graphics::NewImage(char* file, int r, int g, int b) { Image* image = new Image(); image->surf = SDL_DisplayFormat(SDL_LoadBMP(file)); SDL_SetColorKey(image->surf, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(image->surf->format, r, g, b)); return image; } bool Graphics::DrawImage(Image* img, int x, int y) { if(Screen == NULL || img->surf == NULL) return false; SDL_Rect Area; Area.x = x; Area.y = y; SDL_BlitSurface(img->surf, NULL, Screen, &Area); return true; } bool Graphics::DrawImage(Image* img, int x, int y, int startX, int startY, int endX, int endY) { if(Screen == NULL || img->surf == NULL) return false; SDL_Rect Area; Area.x = x; Area.y = y; SDL_Rect SrcArea; SrcArea.x = startX; SrcArea.y = startY; SrcArea.w = endX; SrcArea.h = endY; SDL_BlitSurface(img->surf, &SrcArea, Screen, &Area); return true; } void Graphics::Flip() { SDL_Flip(Screen); SDL_FillRect(Screen,NULL, 0x000000); } В конструкторе инициализируется SDL и создается экран. Функция Flip должна вызываться каждый раз после отрисовки картинок, она представляет получившееся на экран и чистит экран в черный цвет для дальнешней отрисовки. Image.cpp 127 #include "Image.h" int Image::GetWidth() { return surf->w; } int Image::GetHeight() { return surf->h; } Надо изменить Game.h, Game.cpp и main.cpp Game.h #ifndef _GAME_H_ #define _GAME_H_ #include "Project.h" class Graphics; class Game { private: bool run; Graphics* graphics; public: Game(); int Execute(int width, int height); void Exit(); }; #endif Тут мы добавляем указатель на Graphics и в Execute добавляем размер экрана Game.cpp #include "Game.h" Game::Game() { run = true; } int Game::Execute(int width, int height) { graphics = new Graphics(width,height); while(run); SDL_Quit(); 128 return 0; } void Game::Exit() { run = false; } Ничего особенного, разве что не пропустите функцию SDL_Quit для очистки SDL main.cpp #include "Project.h" int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Game game; return game.Execute(500,350); } Создаем экран размером 500 на 350. 1.3. Ввод Создаем Input.h #ifndef _INPUT_H_ #define _INPUT_H_ #include "Project.h" class Input { private: SDL_Event evt; public: void Update(); bool IsMouseButtonDown(byte key); bool IsMouseButtonUp(byte key); POINT GetButtonDownCoords(); bool IsKeyDown(byte key); bool IsKeyUp(byte key); byte GetPressedKey(); bool IsExit(); }; #endif SDL_Event — класс какого-нибудь события, его мы держим в Input'е для того, чтобы не создавать объект этого класса каждый цикл Ниже расположены методы, не представляющие особого интереса. Примечание: методы с окончанием Down вызываются, когда клавиша была нажата, а с окончанием Up — когда 129 опущена. Input.cpp #include "Input.h" void Input::Update() { while(SDL_PollEvent(&evt)); } bool Input::IsMouseButtonDown(byte key) { if(evt.type == SDL_MOUSEBUTTONDOWN) if(evt.button.button == key) return true; return false; } bool Input::IsMouseButtonUp(byte key) { if(evt.type == SDL_MOUSEBUTTONUP) if(evt.button.button == key) return true; return false; } POINT Input::GetButtonDownCoords() { POINT point; point.x = evt.button.x; point.y = evt.button.y; return point; } bool Input::IsKeyDown(byte key) { return (evt.type == SDL_KEYDOWN && evt.key.keysym.sym == key); } bool Input::IsKeyUp(byte key) { return (evt.type == SDL_KEYUP && evt.key.keysym.sym == key); } byte Input::GetPressedKey() { return evt.key.keysym.sym; } bool Input::IsExit() { return (evt.type == SDL_QUIT); } 130 Здесь мы обрабатываем наш объект событий в функции Update, а остальные функции просто проверяют тип события и его значения. Изменяем теперь Game.h и Game.cpp #ifndef _GAME_H_ #define _GAME_H_ #include "Project.h" #include "Graphics.h" class Graphics; #include "Input.h" class Input; class Game { private: bool run; Graphics* graphics; Input* input; public: Game(); int Execute(int width, int height); Graphics* GetGraphics(); Input* GetInput(); void Exit(); }; #endif Как видно, мы добавили указатель на Input и создали методы-возвращатели Graphics и Input Game.cpp #include "Game.h" Game::Game() { run = true; } int Game::Execute(int width, int height) { graphics = new Graphics(width,height); input = new Input(); while(run) { input->Update(); } 131 delete graphics; delete input; SDL_Quit(); return 0; } Graphics* Game::GetGraphics() { return graphics; } Input* Game::GetInput() { return input; } void Game::Exit() { run = false; } Практическая работа № 1.31. Разработка приложения с анимацией Цель работы: рассмотреть способы разработки приложений с анимацией Ход работы Задание: Создать несложную анимацию, по дороге будут ездить на встречу друг другу автомобиль и мото-цикл. Используемые компоненты: TImage (Графический холст) находится на вкладке Additional. TTimer (Таймер) находится на вкладке System. В папке “Picture” расположены изображения fon.bmp, avto.bmp и moto.bmp. Это наши заготовки, которые мы будем использовать в программе. Первый способ 1. Запускаем Delphi и создаем новое приложение: File->New->VCL Forms Application – Delphi. 2. Помещаем на форму 3 компонента TImage. Один в один из них загружаем фон, а в два других изображе-ние мотоцикла и автомобиля соответственно и в режиме таймера будем изменять положения компонетов TImage с изображением автомобиля и мотоцикла относительно фона. 3. В компонент Image1 в свойство Picture загружаем подготовленный нами файл fon.bmp, свойство Align устанавливаем alClient. А форму растянем до размеров фона. 4. В компонент Image2 в свойство Picture загружаем подготовленный нами файл avto.bmp и перемещаем его на дорогу. 5. В компонент Image3 в свойство Picture загружаем подготовленный нами файл moto.bmp и перемещаем его на дорогу. 6. Сравнить вашу форму с примером: 7. В коде программы перед разделом type добавим раздел const и объявим две константы const scr_width = 640; // ширина формы scr_height = 480; // высота формы В разделе var объявим переменные x,y,x1,y1 типа integer. var 132 Form1: TForm1; x,y,x1,y1:integer; 8. Создайте метод procedure TForm1.Timer1Timer и запишите его выполнение procedure TForm1.Timer1Timer(Sender: TObject); begin x:=x+2;//текущая координата + шаг для автомобиля x1:=x1-2;//текущая координата + шаг для мотоцикла if x>scr_width+image2.Width then x:=-image2.Width;// ограничение справа if x1<-image3.Width then x1:=scr_width;// ограничение слева //рисуем image2.Left:=x; image3.Left:=x1; end; 9. В свойствах таймера свойство интервал устанавливаем в пределах от 1 до 100, в зависимости от того какую скорость анимации вы хотите получить. Второй способ Второй способ заключается в том, что мы создаем для нашего случая 4 объекта типа TBitMap, в первый за-гружаем фон, во второй - автомобиль, в третий - мотоцикл, а четвертый будет буфером обмена в котором мы вначале будем формировать картинку, а потом выводить ее на экран. Это необходимо делать для того чтобы избежать мерцания картинки на экране во время движения в результате ее перерисовки. Если эффект мерцания для вас не существенен, то можно выводить изображение сразу на экран. 1. Помещаем на форму компонент TImage и компонент TTimer. 2. Для компонента Image1 свойство Align устанавливаем alClient. А для формы свойство AutoSize устанавливаем True. 3. Объявите константы const scr_width = 640; // ширина экрана scr_height = 480; // высота экрана 4. В описании переменных var объявляем четыре переменных для хранения графических картинок, тип tbitmap var fon:tbitmap;//Графический образ Фона avto:tbitmap;//Графический образ автомобиля moto:tbitmap;//Графический образ мотоцикла scr_buffer:tbitmap;//Графический образ автомобиля x,y,x1,y1:integer;//координаты автомобиля и мотоцикла 5. Для того чтобы вывести на экран изображения нужно : а) Активировать созданные переменные //создаем объекты fon:=TBitmap.Create; // фон moto:=TBitmap.Create;// мотоцикл avto:=TBitmap.Create; // машина scr_buffer:=TBitmap.Create; // буфер обмена scr_buffer.Width:=scr_width; // ширина буфера scr_buffer.Height:=scr_height; // высота буфера б) Загрузить изображения в эти переменные // загружаем объекты moto.LoadFromFile('moto.bmp'); // мотоцикл avto.LoadFromFile('avto.bmp'); // машина fon.LoadFromFile('fon.bmp');// фон x:=0; //начальные координаты машины y:=430; x1:=500;// начальные координаты мотоцикла 133 y1:=380; в) Установить прозрачный фон вокруг машины и мотоцикла avto.transparent:=true;//задаем прозрачность moto.transparent:=true; г) Вывод изображения на графический холст Image //Определение ление координат x:=x+2;//текущая координата + шаг для автомобиля x1:=x1-2;//текущая координата + шаг для мотоцикла if x>scr_width+avto.Width then x:=-avto.Width;// ограничение справа if x1<-moto.Width then x1:=scr_width;// ограничение слева //рисуем scr_buffer.Canvas.Draw(0,0,fon);//возобновление фона scr_buffer.Canvas.Draw(x1,y1,moto);//движение мотоцикла scr_buffer.Canvas.Draw(x,y,avto);//движение машины form1.Canvas.Draw(0,0,scr_buffer); //копируем содержимое буфера на экран При этом первая цифра в скобках, это координата x, а вторая цифра соответственно координата y д) Для того , чтобы изображения стали двигаться, необходимо динамически менять координаты изобра-жений на холсте, желательно стирая старое изображение. Эту задачу выполняет компонент Timer. Практическая работа № 1.32. Оптимизация кода Цель работы: изучить технологию оптимизации программного кода Ход работы Задание: Модифицируйте 2 программы, реализованные на C++: 1 программа #include { int number; setlocale(LC_CTYPE,"Russian"); cout << "Введите число: "; cin >> number; cin.ignore(); cout << "Вы ввели: "<< number <<"\n"; cin.get(); } Описание: пользователю предлагаеться ввести цифру, но если он введет например: b6, то ему выдаст - "Вы ввели: 5 (Только номер). Необходимо добиться, чтобы программа различала отрицательные и положительные значения, цифры и буквы, а также автоматически выдавала значение введенного числа в квадрате. 2 программа #include /* Библиотека (стандарт) */ #include + int main(int argc, char* argv[]) { setlocale(LC_CTYPE,"Russian"); double plus, minus, pow, div; // объявление переменных через запятую double a1; // отдельное объявление переменной a1 double a2; // отдельное объявление переменной a2 cout << "Введите первое число: "; cin >> a1; 134 cout << "Введите второе число: "; cin >> a2; plus = a1 + a2; // операция сложения minus = a1 - a2; // операция вычитания pow = a1 * a2; // операция умножения div = a1 / a2; // операция деления cout << a1 << "+" << a2 << "=" << plus << endl; cout << a1 << "-" << a2 << "=" << minus << endl; cout << a1 << "*" << a2 << "=" << pow << endl; cout << a1 << "/" << a2 << "=" << div << endl; system("pause"); return 0; } Описание: простой калькулятор, который может: добавлять, вычитать, умножать и делить. Необходимо реализовать функцию возведения числа в любую степень, а также умножение отрицательных чисел. |