Читайте также: |
|
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ////////////////////////////////////////
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <bios.h>
#include <fcntl.h>
#include <memory.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include "graph0.h" // включаем нашу графическую библиотеку
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ //////////////////////////////////
sprite object;
pcx_picture text_cells;
// ФУНКЦИИ ///////////////////////////////////////////////
void Scale_Sprite(sprite_ptr sprite,float scale)
{
// эта функция масштабирует спрайт, рассчитывая количество
// дублирования исходных пикселей, необходимое для получения
// требуемого размера
char far *work_sprite;
int work offset=0, offset,x,у;
unsigned char data;
float y_scale_index,x_scale_step,y_scale_step,x_scale_index;
// берем первый пиксель исходного изображения
y_scale_index = 0;
// рассчитываем дробный шаг
y_scale_step = sprite height/scale;
x_scale_step = sprite_width/scale;
// для простоты даем указателю иа спрайт новое имя
work_sprite = sprite->frames [sprite->curr__frame];
// расчет смещения спрайта в видеобуфере
offset = (sprite->y << 8) + (sprite->y << 6) + sprite->x;
// построчно масштабируем спрайт
for (y=0; y<(int) (scale); у++)
{
// копируем следующую строчку в буфер экрана
х_scale_index=0;
for (х=0; x<(int)scale; х++)
{
// проверка на прозрачность пикселя
// (то есть равен ли он 0), если нет - прорисовываем пиксель
if ((data=work_sprite[work_offset+(int)x_scale_index]))
double_buffer[offset+x] = data;
x_scale_index+=(x_scale_step);
} // конец внутреннего цикла (по X)
// используя дробный шаг приращения, определяем следующий
// пиксель исходного изображения
у_scale_index+=y_scale_step;
// переходим к следующей строке видеобуфера
//и растрового буфера спрайта
offset += SCREEN_WIDTH;
work_offset = sprite_width*(int)(y_scale_index);
} // конец внешнего цикла (по У)
} // end Scale_Sprite /////////////////////////////////////////
void Clear_Double_Buffer(void)
// эта функция очищает дублирующий буфер
// несколько грубо, зато работает
_fmemset(double_buffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT +1);
} // конец Clear_Double_Buffer
// ОСНОВНАЯ ПРОГРАММА /////////////////////////////////////
void main(void)
{
int index, done=0;
float scale=64;
// установка видеорежима 320х200х256
Set_Mode(VGA256);
// установка размера спрайта
sprite_width = sprite_height = 64;
// инициализация файла PCX, который содержит
// мультииликационные кадры
PCX__Init ((pcx_picture_ptr)&text_cells);
// загрузка файла PCX, который содержит мультипликационные кадры
PCX_Load("textures.pcx", (pcx_picture_ptr)&text_cells,1);
// PCX_Show_Buffer((pcx_picture_ptr)&text_cells);
Sprite_Init ((sprite_ptr) &object, 0, 0, 0, 0,0, 0);
// выборка четырех интересующих нас текстур
PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,
(sprite_ptr)&object,0,0,0);
PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,
(sprite_ptr)&object,1,1,0);
PCX_Grap_Bitmap((pcx_picture_ptr)&text cells,
(sprite_ptr)&object,2,2,0);
PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,
(sprite_ptr)&object,3,3,0);
// резервируем память под дублирующий буфер
Init_Double_Buffer();
// позиционируем объект в центре экрана
object.curr frame =0;
object.х = 160-(sprite_width>>1);
object.у = 100-(sprite height>>1);
// очищаем дублирующий буфер
Clear_Double_Buffer();
// воспроизводим масштабированную текстуру
Scale_Sprite((sprite_ptr)&object,scale);
Show_Double_Buffer(double buffer);
_settextposition(24,0);
Printf("Q - Quit, < > - Scale, Space - Toggle.");
// главный цикл while(!done)
{
// нажал ли игрок клавишу?
if (kbhit())
{
switch(getch()) {
case '.': // увеличиваем объект
{
if (scale<180) (scale+=4;
object.x-=2;
object.y-=2;
} // конец оператора if
} break;
case ',': // уменьшаем объект
{
if (scale>4) {
scale-=4;
object.x+=2;
object.y+=2;
} // конец оператора if
} break;
case ' ': // смена текстуры
{
// текстуры исчерпались?
if (++object.curr_frame==4)
object. curr_frame=0;
} break;
case 'q': // до свидания! {
done=1;
) break;
default:break;
} // конец оператора switch
// очистка дублирующего буфера
Clear_Double_Buffer();
// масштабирование спрайта и прорисовка его
//в дублирующем буфере
Scale_Sprite((sprite_ptr)&object,scale);
// вывод дублирующего буфера на экран
Show_Double_Buffer(double_buffer);
_settextpostion(24,0);
printf("Q - Quit,"< > - Scale, Space - Toggle.");
}// конец оператора,if
} // конец оператора..while
// удаление файла PCX
PCX_Delete((pcx_picture_ptr)&text_cells);
// возврат в текстовый режим
Set_Mode(TEXT_MODE);
} // конец функции main
Повороты объектов
Хотя мы и не собираемся вращать многочисленные растровые изображения, для полноты картины познакомимся с основными принципами этого процесса.
Вращение битовых объектов до сих пор еще не до конца исследованная область. Инженеры и программисты и по сей день пытаются найти наиболее эффективные алгоритмы для этой операции. Проблема заключается в том, что битовый образ - это конгломерат сотни, если не тысячи пикселей и чтобы повернуть образ, нам надо правильно произвести поворот каждой из этих точек, Обычно это связано с довольно сложными математическими преобразованиями, которые выполняются на персональном компьютере не очень-то быстро. Вы можете спросить: «А как же это сделал Крис Роберте в игре Wing Commander?» Очень просто: он заранее получил все возможные повороты всех космических кораблей с помощью программы моделирования, а потом просто занес их в гигантскую таблицу. Единственная операция, которая могла бывыполняться долго ~ масштабирование, тоже была произведена заранее, а результаты также занесены в таблицу. Я всегда действую подобным же образом и вам советую заранее создать все варианты поворотов ваших изображений, используя один из двух пакетов, либо Deluxe Paint фирмы Electronic Arts или, если вам нравится тратить деньги, 3D Studio фирмы AutoDesk. Затем поместите их в таблицу, и пусть ваша программа извлекает изображения из этой таблицы, используя угол поворота, как индекс. Отрицательная сторона этого метода - не очень рациональное использование памяти. Хранение 32 или 64 битных образов для всех возможных объектов отъедает существенный кусок памяти. Однако можно использовать частичные а не полные таблицы. Например, вы можете поместить в таблицу только кадры для одного квадранта, а для других симметричных квадрантов генерировать изображения уже во время игры. Так как поворот вокруг осей Х и Y делается очень просто — такой метод используется очень часто.
Чтобы показать пример поворота растрового изображения с помощью таблиц, я написал программу, которая использует нашу функцию масштабирования для файла PCX, содержащего несколько кадров с летящим астероидом. Эта программа, которую я назвал AFIELD.С, передвигает астероид по трехмерному звездному полю, масштабируя его по мере приближения или удаления оигрока. Листинг 7.11 содержит текст этой программы.
Дата добавления: 2015-07-12; просмотров: 117 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Листинг 7.9. Эффекты экрана (SCREENFX.C). | | | Листинг 7.11. Трехмерный астероид (AFIELD.С). |